diff options
Diffstat (limited to 'gcc/rust')
355 files changed, 41521 insertions, 10904 deletions
diff --git a/gcc/rust/ChangeLog b/gcc/rust/ChangeLog index d6f94f5..5cb9311 100644 --- a/gcc/rust/ChangeLog +++ b/gcc/rust/ChangeLog @@ -1,3 +1,4666 @@ +2025-04-28 Owen Avery <powerboat9.gamer@gmail.com> + + * checks/errors/borrowck/rust-bir-place.h + (IndexVec::size_type): Add. + (IndexVec::MAX_INDEX): Add. + (IndexVec::size): Change the return type to the type of the + internal value used by the index type. + (PlaceDB::lookup_or_add_variable): Use the return value from the + PlaceDB::add_place call. + * checks/errors/borrowck/rust-bir.h + (struct BasicBlockId): Move this definition before the + definition of the struct Function. + +2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * ast/rust-ast-visitor.cc (DefaultASTVisitor::visit): Visit visibility. + +2025-04-28 Owen Avery <powerboat9.gamer@gmail.com> + + * ast/rust-ast-visitor.cc + (DefaultASTVisitor::visit): Visit the loop labels of + WhileLetLoopExpr instances before visiting their scrutinee + expressions. + * resolve/rust-early-name-resolver-2.0.cc + (Early::resolve_glob_import): Pass the glob import's path + directly to NameResolutionContext::resolve_path. + * resolve/rust-toplevel-name-resolver-2.0.cc + (TopLevel::visit): Remove unnecessary call to + Identifier::as_string. + (flatten_glob): Improve handling of cases where a glob use tree + has no path. + +2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * expand/rust-derive-clone.cc (DeriveClone::clone_enum_struct): Clone + path to avoid using the same nodeid. + +2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * ast/rust-ast-visitor.cc (DefaultASTVisitor::visit_function_params): + Add specialized function to visit function parameters. + (DefaultASTVisitor::visit): Remove parameter visit and call specialized + function instead. + * ast/rust-ast-visitor.h: Add function prototye. + * resolve/rust-late-name-resolver-2.0.cc (Late::visit): Remove + function. + (Late::visit_function_params): Override specialized visit function. + * resolve/rust-late-name-resolver-2.0.h: Add overriden function + prototype. + +2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * resolve/rust-name-resolution-context.h: Use BindingLayer instead. + * resolve/rust-name-resolution-context.cc (BindingLayer::BindingLayer): + Add new constructor for binding layer. + (BindingLayer::bind_test): Add a function to test a binding constraint. + (BindingLayer::push): Push a new binding group. + (BindingLayer::and_binded): Add function to test and-binding + constraint. + (BindingLayer::or_binded): Add function to test or-binding constraints. + (BindingLayer::insert_ident): Insert a new identifier in the current + binding group. + (BindingLayer::merge): Merge current binding group with it's parent. + (BindingLayer::get_source): Get the source of the current binding + group. + * resolve/rust-late-name-resolver-2.0.cc: Use stacked context for + binding group. + * util/rust-stacked-contexts.h: Add mutable peek function. + +2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * resolve/rust-late-name-resolver-2.0.cc (Late::visit): Add binding + creation in visitor. + * resolve/rust-late-name-resolver-2.0.h: Add function prototypes. + * resolve/rust-name-resolution-context.h: Add binding context. + +2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * resolve/rust-name-resolution-context.h (struct Binding): Add Binding + struct to differentiate Or and Product bindings in patterns. + (enum class): Add Binding kind. + (class BindingContext): Add binding context with Binding stack. + +2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * ast/rust-ast.h: Add hash function. + +2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * ast/rust-ast.h: Add equality operator. + +2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * resolve/rust-default-resolver.cc (DefaultResolver::visit): Add visit + function for TypeParam. + * resolve/rust-default-resolver.h: Add function prototype. + * resolve/rust-forever-stack.h: Add function to check for forward + declaration ban. + * resolve/rust-late-name-resolver-2.0.cc (Late::visit): Check forward + declarations. + +2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * ast/rust-ast-collector.cc (TokenCollector::visit): Remove error kind + and change function call. + * ast/rust-ast-visitor.cc (DefaultASTVisitor::visit): Change call name. + * ast/rust-path.cc (ConstGenericParam::as_string): Likewise. + * ast/rust-path.h: Remove error kind. + * hir/rust-ast-lower-type.cc (ASTLowerGenericParam::visit): Change call + name. + * parse/rust-parse-impl.h (Parser::parse_generic_param): Use optional + on parsing failure. + (Parser::parse_generic_arg): Likewise. + (Parser::parse_path_generic_args): Likewise. + * parse/rust-parse.h: Likewise. + * resolve/rust-ast-resolve-type.h: Change call name. + +2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * resolve/rust-late-name-resolver-2.0.cc (Late::visit): Change error + message. + +2025-04-28 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-early-name-resolver-2.0.cc + (Early::build_import_mapping): Avoid outputting an "unresolved + import" error if other errors are outputted during resolution. + * resolve/rust-early-name-resolver-2.0.h + (Early::resolve_path_in_all_ns): Collect path resolution errors + while avoiding duplicate errors for resolutions in each + namespace. + * resolve/rust-forever-stack.h + (ForeverStack::resolve_path): Add parameter for collecting + errors. + (ForeverStack::find_starting_point): Likewise. + (ForeverStack::resolve_segments): Likewise. + * resolve/rust-forever-stack.hxx + (check_leading_kw_at_start): Likewise. + (ForeverStack::find_starting_point): Likewise. + (ForeverStack::resolve_segments): Likewise. + (ForeverStack::resolve_path): Likewise. + * resolve/rust-name-resolution-context.h + (NameResolutionContext::resolve_path): Add optional parameter + for collecting errors. + +2025-04-28 Philip Herron <herron.philip@googlemail.com> + + * backend/rust-compile-expr.cc (CompileExpr::array_copied_expr): prealloc the vector + +2025-04-28 Philip Herron <herron.philip@googlemail.com> + + * ast/rust-ast-visitor.cc (DefaultASTVisitor::visit): add guard + * expand/rust-expand-visitor.cc (ExpandVisitor::visit): add guard + +2025-04-28 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-ast-resolve-path.cc + (ResolvePath::resolve_path): Adjust error messages. + * resolve/rust-ast-resolve-type.cc + (ResolveRelativeTypePath::go): Likewise. + * resolve/rust-forever-stack.hxx + (check_leading_kw_at_start): Likewise. + +2025-04-28 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit): fix bad assertion + +2025-04-28 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-forever-stack.hxx + (ForeverStack::resolve_path): Pass instance of Node to lambda by + reference instead of by value. + +2025-04-28 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-hir-type-check-struct-field.h: keep reference to parent expression + * typecheck/rust-hir-type-check-struct.cc (TypeCheckStructExpr::TypeCheckStructExpr): + update ctor + (TypeCheckStructExpr::resolve): remove bad rust_fatal_errors + (TypeCheckStructExpr::visit): cleanup errors + +2025-04-28 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-late-name-resolver-2.0.cc + (Late::visit): Handle StructPatternFieldIdent. + * resolve/rust-late-name-resolver-2.0.h + (Late::visit): Likewise. + +2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * ast/rust-ast-collector.cc (TokenCollector::visit): Dump llvm inline + asm tokens. + +2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * ast/rust-ast-collector.cc (TokenCollector::visit): Remove unreachable + code. + * ast/rust-expr.h (struct LlvmOperand): Add LlvmOperand struct to + represent input and outputs. + (class LlvmInlineAsm): Add input, output and clobber operands. + (struct TupleTemplateStr): Add locus getter. + * backend/rust-compile-block.h: Add visit for LlvmInlineAsm. + * backend/rust-compile-expr.cc (CompileExpr::visit): Add llvm inline + asm stmt compilation. + * backend/rust-compile-expr.h: Add function prototype. + * backend/rust-compile-asm.h (class CompileLlvmAsm): Add llvm asm hir + not to gimple. + * backend/rust-compile-asm.cc (CompileLlvmAsm::CompileLlvmAsm): Add + constructor. + (CompileLlvmAsm::construct_operands): Add function to construct operand + tree. + (CompileLlvmAsm::construct_clobbers): Add function to construct clobber + tree. + (CompileLlvmAsm::tree_codegen_asm): Generate the whole tree for a given + llvm inline assembly node. + * checks/errors/borrowck/rust-bir-builder-expr-stmt.cc (ExprStmtBuilder::visit): + Add visit function. + * checks/errors/borrowck/rust-bir-builder-expr-stmt.h: Add function + prototype. + * checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h: Add visit + function. + * checks/errors/borrowck/rust-bir-builder-struct.h: Likewise. + * checks/errors/borrowck/rust-function-collector.h: Likewise. + * checks/errors/privacy/rust-privacy-reporter.cc (PrivacyReporter::visit): + Likewise. + * checks/errors/privacy/rust-privacy-reporter.h: Add visit function + prototype. + * checks/errors/rust-const-checker.cc (ConstChecker::visit): Add visit + function. + * checks/errors/rust-const-checker.h: Add visit function prototype. + * checks/errors/rust-hir-pattern-analysis.cc (PatternChecker::visit): + Add visit function. + * checks/errors/rust-hir-pattern-analysis.h: Add visit function + prototype. + * checks/errors/rust-unsafe-checker.cc (UnsafeChecker::visit): Add + visit function. + * checks/errors/rust-unsafe-checker.h: Add function prototype. + * expand/rust-macro-builtins-asm.cc (parse_llvm_templates): Parse + templates. + (parse_llvm_arguments): Add function to parse non template tokens. + (parse_llvm_operands): Add function to parse operands, either input or + output. + (parse_llvm_outputs): Add function to parse and collect llvm asm + outputs. + (parse_llvm_inputs): Likewise with inputs. + (parse_llvm_clobbers): Add function to parse llvm asm clobbers. + (parse_llvm_options): Add function to parse llvm asm options. + (parse_llvm_asm): Add function to parse llvm asm. + * expand/rust-macro-builtins-asm.h (class LlvmAsmContext): Add context + for llvm asm parser. + (parse_llvm_outputs): Add function prototype. + (parse_llvm_inputs): Likewise. + (parse_llvm_clobbers): Likewise. + (parse_llvm_options): Likewise. + * hir/rust-ast-lower-expr.cc (ASTLoweringExpr::visit): Lower AST llvm + asm node to HIR. + * hir/rust-ast-lower-expr.h: Add function prototype. + * hir/rust-hir-dump.cc (Dump::visit): Add visit function. + * hir/rust-hir-dump.h: Add function prototype. + * hir/tree/rust-hir-expr-abstract.h: Add HIR llvm asm node kind. + * hir/tree/rust-hir-expr.h (struct LlvmOperand): Add LlvmOperand type + to represent input and outputs. + (class LlvmInlineAsm): Add LlvmInlineAsm hir node. + * hir/tree/rust-hir-full-decls.h (class LlvmInlineAsm): Add + LlvmInlineAsm hir node forward declaration. + * hir/tree/rust-hir-visitor.h: Add visit functions for LlvmInlineAsm + hir node. + * hir/tree/rust-hir.cc (LlvmInlineAsm::accept_vis): Add hir node + visitor related functions. + * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit): + Type check input and output operands. + * typecheck/rust-hir-type-check-expr.h: Add function prototype. + * ast/rust-ast-visitor.cc (DefaultASTVisitor::visit): Visit input and + output operand expressions. + * resolve/rust-ast-resolve-expr.cc (ResolveExpr::visit): Resolve input + and output expressions. + * resolve/rust-ast-resolve-expr.h: Add function prototypes. + +2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * ast/rust-ast-collector.cc (TokenCollector::visit): Make visitor + unreachable. + * ast/rust-ast-collector.h: Add visit for LlvmInlineAsmNode. + * ast/rust-ast-visitor.cc (DefaultASTVisitor::visit): Add visit + function for the default ast visitor. + * ast/rust-ast-visitor.h: Add function prototype. + * ast/rust-ast.cc (LlvmInlineAsm::accept_vis): Add accept_vis to + LlvmInlineAsm node. + * ast/rust-ast.h: Add LlvmInlineAsm node kind. + * ast/rust-expr.h (class LlvmInlineAsm): Add LlvmInlineAsm node. + * expand/rust-derive.h: Add visit function for LlvmInlineAsm node. + * expand/rust-macro-builtins-asm.cc (MacroBuiltin::llvm_asm_handler): + Add handler for llvm inline assembly nodes. + (parse_llvm_asm): Add function to parse llvm assembly nodes. + * expand/rust-macro-builtins-asm.h (parse_llvm_asm): Add function + prototypes. + * expand/rust-macro-builtins.cc (inline_llvm_asm_maker): Add macro + transcriber. + * expand/rust-macro-builtins.h: Add transcriber function prototype. + * hir/rust-ast-lower-base.cc (ASTLoweringBase::visit): Add visit + function for LlvmInlineAsm node. + * hir/rust-ast-lower-base.h: Add visit function prototype. + * resolve/rust-ast-resolve-base.cc (ResolverBase::visit): Add visit + function for LlvmInlineAsm node. + * resolve/rust-ast-resolve-base.h: Add visit function prototype. + +2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * expand/rust-macro-builtins-asm.cc (parse_asm_arg): Emit error + message. + +2025-04-28 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-hir-type-check-item.cc (TypeCheckItem::visit): add diagnostic + * typecheck/rust-tyty.cc (BaseType::contains_infer): new helper to grab first infer var + * typecheck/rust-tyty.h: prototype + +2025-04-28 Philip Herron <herron.philip@googlemail.com> + + * rust-gcc.cc (arithmetic_or_logical_expression): Ensure this is an integer + +2025-04-28 Philip Herron <herron.philip@googlemail.com> + + * hir/rust-hir-dump.cc (Dump::visit): add guard for optional label + +2025-04-28 Yap Zhi Heng <yapzhhg@gmail.com> + + * typecheck/rust-tyty.h: Remove extra redundant comment. + * typecheck/rust-hir-type-check-base.cc: Update comment on repr + handling. + +2025-04-28 Zhi Heng <yapzhhg@gmail.com> + + * typecheck/rust-hir-type-check-base.cc: Set enum representing + type properly if repr is an integer type. + * typecheck/rust-hir-type-check-item.cc: Update comments. + +2025-04-28 Zhi Heng <yapzhhg@gmail.com> + + * typecheck/rust-tyty.h: Add new `ReprKind` enum to + `ReprOptions`. + * typecheck/rust-hir-type-check-base.cc: Handle setting of + `repr_kind`. + * typecheck/rust-hir-type-check-item.cc: New check for + zero-variant enums. + +2025-04-28 Philip Herron <herron.philip@googlemail.com> + + * checks/errors/rust-unsafe-checker.cc (UnsafeChecker::visit): add null check + * hir/tree/rust-hir-item.h: add has_type helper + * typecheck/rust-hir-trait-resolve.cc (TraitItemReference::resolve_item): + add missing type checking + +2025-04-14 Arthur Cohen <arthur.cohen@embecosm.com> + + * util/rust-lang-item.h: Add new manually_drop lang item. + * util/rust-lang-item.cc: Likewise. + +2025-04-14 Arthur Cohen <arthur.cohen@embecosm.com> + + * util/rust-attribute-values.h: Add RUSTFMT value. + * util/rust-attributes.cc: Define the attribute. + * util/rust-attributes.h (enum CompilerPass): Add EXTERNAL variant. + * expand/rust-macro-builtins.cc: Fix formatting. + +2025-04-14 Arthur Cohen <arthur.cohen@embecosm.com> + + * resolve/rust-early-name-resolver-2.0.cc (Early::visit_attributes): Remove assertion. + +2025-04-14 Arthur Cohen <arthur.cohen@embecosm.com> + + * util/rust-attribute-values.h: Add missing attributes. + * util/rust-attributes.cc: Likewise. + * util/rust-attributes.h (enum CompilerPass): Mention adding something for const + functions. + +2025-04-14 beamandala <mandalapubhavesh@gmail.com> + + * expand/rust-macro-builtins.cc (MacroBuiltin::builtin_transcribers): + Add entry for track_caller. + * util/rust-attribute-values.h: add `TRACK_CALLER` attribute. + * util/rust-attributes.cc: add `track_caller` attribute definition. + +2025-04-14 Owen Avery <powerboat9.gamer@gmail.com> + + * checks/errors/rust-const-checker.cc + (ConstChecker::visit): Visit the enum items of enums. + * resolve/rust-ast-resolve-item.cc + (ResolveItem::visit): Resolve enum discriminants during nr1.0. + +2025-04-14 Arthur Cohen <arthur.cohen@embecosm.com> + + * expand/rust-macro-builtins-format-args.cc (format_args_parse_arguments): Improve safety, + allow extra commas after end of argument list. + +2025-04-14 Arthur Cohen <arthur.cohen@embecosm.com> + + * expand/rust-macro-expand.cc (MacroExpander::expand_decl_macro): Call into + TokenTreeDesugar. + * expand/rust-token-tree-desugar.cc: New file. + * expand/rust-token-tree-desugar.h: New file. + * Make-lang.in: Compile them. + +2025-04-14 Arthur Cohen <arthur.cohen@embecosm.com> + + * expand/rust-macro-expand.cc (MacroExpander::match_n_matches): Do not + insert fragments and substack fragments if the matcher failed. + +2025-04-14 Arthur Cohen <arthur.cohen@embecosm.com> + + * rust-session-manager.cc (Session::compile_crate): Call the visitor later in the pipeline. + +2025-04-14 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-ast.h (DelimTokenTree::get_locus): New function. + +2025-04-14 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-expr.h (class RangeExpr): Add empty outer attributes and allow getting them + and setting them. + +2025-04-14 Arthur Cohen <arthur.cohen@embecosm.com> + + * resolve/rust-toplevel-name-resolver-2.0.cc (TopLevel::visit): Return if module + is unloaded. + +2025-04-14 Arthur Cohen <arthur.cohen@embecosm.com> + + * typecheck/rust-hir-type-check-expr.cc (is_default_fn): New. + (emit_ambiguous_resolution_error): New. + (handle_multiple_candidates): Properly handle multiple candidates in + the case of specialization. + (TypeCheckExpr::visit): Call `handle_multiple_candidates`. + +2025-04-14 Andrew Pinski <quic_apinski@quicinc.com> + + PR rust/119342 + * rust-gcc.cc (block): Add comment on why chaining + the variables of the scope toether. + +2025-04-14 Andrew Pinski <quic_apinski@quicinc.com> + + PR rust/119341 + * rust-gcc.cc (function_type): Use range fors. + (function_type_variadic): Likewise. + (fill_in_fields): Likewise. + (statement_list): Likewise. + (block): Likewise. + (block_add_statements): Likewise. + (function_set_parameters): Likewise. + (write_global_definitions): Likewise. + +2025-04-14 Andrew Pinski <quic_apinski@quicinc.com> + + * rust-gcc.cc (Bvariable::get_tree): Use error_operand_p. + (pointer_type): Likewise. + (reference_type): Likewise. + (immutable_type): Likewise. + (function_type): Likewise. + (function_type_variadic): Likewise. + Cleanup the check for receiver.type first. + (function_ptr_type): Use error_operand_p. + (fill_in_fields): Likewise. + (fill_in_array): Likewise. + (named_type): Likewise. + (type_size): Likewise. + (type_alignment): Likewise. + (type_field_alignment): Likewise. + (type_field_offset): Likewise. + (zero_expression): Likewise. + (float_constant_expression): Likewise. + (convert_expression): Likewise. + (struct_field_expression): Likewise. + (compound_expression): Likewise. + (conditional_expression): Likewise. + (negation_expression): Likewise. + (arithmetic_or_logical_expression): Likewise. + (arithmetic_or_logical_expression_checked): Likewise. + (comparison_expression): Likewise. + (lazy_boolean_expression): Likewise. + (constructor_expression): Likewise. + (array_constructor_expression): Likewise. + (array_index_expression): Likewise. + (call_expression): Likewise. + (init_statement): Likewise. + (assignment_statement): Likewise. + (return_statement): Likewise. + (exception_handler_statement): Likewise. + (if_statement): Likewise. + (compound_statement): Likewise. + Tighten up the code, removing t variable. + (statement_list): Use error_operand_p. + (block): Likewise. + (block_add_statements): Likewise. + (convert_tree): Likewise. + (global_variable): Likewise. + (global_variable_set_init): Likewise. + (local_variable): Likewise. + (parameter_variable): Likewise. + (static_chain_variable): Likewise. + (temporary_variable): Likewise. + (function): Likewise. Tighten up the code. + (function_defer_statement): Use error_operand_p. + (function_set_parameters): Use error_operand_p. + (write_global_definitions): Use error_operand_p. + Tighten up the code around the loop. + +2025-04-14 Andrew Pinski <quic_apinski@quicinc.com> + + * rust-gcc.cc (is_floating_point): Use FLOAT_TYPE_P + instead of manually checking the type. + +2025-04-08 Matty Kuhn <matty.kuhn.1@gmail.com> + + * ast/rust-ast.h: (AST::Attribute): add empty_input function + * checks/errors/rust-feature-gate.cc: (FeatureGate::visit): check for empty feature gate + +2025-04-08 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * ast/rust-ast-collector.cc (TokenCollector::visit): Update label + getter call. + * ast/rust-ast-visitor.cc (DefaultASTVisitor::visit): Likewise. + * ast/rust-ast.cc (BreakExpr::as_string): Likewise. + * hir/rust-ast-lower-expr.cc (ASTLoweringExpr::visit): Likewise. + * resolve/rust-ast-resolve-expr.cc (ResolveExpr::visit): Likewise. + * resolve/rust-late-name-resolver-2.0.cc (Late::visit): Likewise. + * ast/rust-expr.h: Add optional getter and rename label getter to + get_label_unchecked. + +2025-04-08 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * ast/rust-ast-collector.cc (TokenCollector::visit): + Call unchecked getter. + * ast/rust-ast-visitor.cc (DefaultASTVisitor::visit): + Likewise. + * ast/rust-ast.cc (ContinueExpr::as_string): Likewise. + * hir/rust-ast-lower-expr.cc (ASTLoweringExpr::visit): Likewise. + * resolve/rust-ast-resolve-expr.cc (ResolveExpr::visit): Likewise. + * resolve/rust-late-name-resolver-2.0.cc (Late::visit): Likewise. + * ast/rust-expr.h: Add new getter for the optional and rename getter + to get_label_unchecked. + +2025-04-08 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * parse/rust-parse-impl.h (Parser::parse_loop_label): Change function + return type to expected. + (Parser::parse_labelled_loop_expr): Adapt call location to new return + type. + * parse/rust-parse.h (enum class): Update function prototype. + +2025-04-08 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * resolve/rust-late-name-resolver-2.0.cc (Late::visit): Add call + to label resolution if there is one label. + (Late::resolve_label): Look for labels and emit an error message on + failure. + * resolve/rust-late-name-resolver-2.0.h: Add function prototypes. + +2025-04-08 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * resolve/rust-ast-resolve-expr.cc (ResolveExpr::visit): + Change error message to match rustc. + +2025-04-08 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * ast/rust-ast-builder.cc (Builder::self_ref_param): Remove error state + and use optional. + * ast/rust-ast-visitor.cc (DefaultASTVisitor::visit): Check label + before visiting. + * ast/rust-ast.cc (ContinueExpr::as_string): Retrieve label value. + (Lifetime::as_string): Retrieve lifetime value. + (ReferenceType::as_string): Likewise. + (SelfParam::as_string): Likewise. + * ast/rust-ast.h: Remove lifetime and LifetimeParam error state. + * ast/rust-desugar-for-loops.cc (DesugarForLoops::DesugarCtx::make_break_arm): + Use optional instead of error state. + * ast/rust-expr.h (class ContinueExpr): Make label optional. + * ast/rust-item.h (class SelfParam): Make lifetime optional. + * ast/rust-type.h (class ReferenceType): Likewise. + * backend/rust-compile-base.cc: Use optional for self param instead + of error state. + * backend/rust-compile-base.h: Update function prototype. + * expand/rust-derive-clone.cc (DeriveClone::clone_fn): Use optional. + * hir/rust-ast-lower-base.cc (ASTLoweringBase::lower_self): Lower + lifetime only if it exists. + * hir/rust-ast-lower-block.h: Lower loop label only if it exists. + * hir/rust-ast-lower-expr.cc (ASTLoweringExpr::visit): Likewise. + * hir/rust-ast-lower-implitem.cc (ASTLowerImplItem::visit): Remove + references to error state. + (ASTLowerTraitItem::visit): Lower self param only if it exists. + * hir/rust-ast-lower-item.cc (ASTLoweringItem::visit): Use nullopt + for default value instead of SelfParam error state. + * hir/rust-ast-lower.cc (ASTLoweringExprWithBlock::visit): Lower label + only if it exists. + * hir/rust-hir-dump.cc (Dump::do_traitfunctiondecl): Print self only if + it exists. + (Dump::visit): Liewise. + * hir/tree/rust-hir-bound.h: Remove error state. + * hir/tree/rust-hir-expr.cc (ContinueExpr::ContinueExpr): Use optional + in constructor for loop label. + (BreakExpr::BreakExpr): Likewise. + * hir/tree/rust-hir-expr.h (class ContinueExpr): Remove error state + implementation. + (class BreakExpr): Likewise. + * hir/tree/rust-hir-generic-param.h: Likewise. + * hir/tree/rust-hir-item.cc (SelfParam::SelfParam): Make lifetime + optional. + (Function::Function): Make self param optional. + * hir/tree/rust-hir-item.h (class Function): Likewise. + * hir/tree/rust-hir-type.cc (ReferenceType::ReferenceType): Make + lifetime optional. + * hir/tree/rust-hir-type.h (class ReferenceType): Likewise. + * hir/tree/rust-hir.cc (ContinueExpr::as_string): Use new getter. + (BreakExpr::as_string): Likewise. + (Lifetime::as_string): Likewise. + (ReferenceType::as_string): Likewise. + (TraitFunctionDecl::as_string): Likewise. + (SelfParam::as_string): Remove error state checking. + * parse/rust-parse-impl.h (Parser::parse_generic_param): Adapt to + optional. + (Parser::parse_lifetime_params): Likewise. + (Parser::parse_lifetime_params_objs): Likewise. + (Parser::parse_lifetime_param): Likewise. + (Parser::parse_lifetime_where_clause_item): Likewise. + (Parser::parse_type_param_bound): Likewise. + (Parser::parse_lifetime_bounds): Likewise. + (Parser::parse_path_generic_args): Likewise. + (Parser::parse_self_param): Likewise. + (Parser::parse_break_expr): Likewise. + (Parser::parse_continue_expr): Likewise. + (Parser::parse_reference_type_inner): Likewise. + * parse/rust-parse.h (class ParseLifetimeParamError): Add new class for + lifetime param parsing errors. + (class ParseLifetimeError): Add new class for lifetime parsing errors. + (enum ParseSelfError): Add new class for self param parsing errors. + * typecheck/rust-hir-type-check-implitem.cc (TypeCheckImplItem::visit): + Use unchecked getter in checked context. And make anonymous region. + * typecheck/rust-hir-type-check.cc (TraitItemReference::get_type_from_fn): + Likewise. + +2025-04-08 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * ast/rust-ast-visitor.cc (DefaultASTVisitor::visit): Add + check for loop label before visiting it. + +2025-04-08 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * ast/rust-expr.h: Remove error getter and constructor. + +2025-04-08 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * ast/rust-ast-builder.cc (Builder::block): Call with a nullopt instead + of an error loop label. + (WhileLetLoopExpr::as_string): Use getter function and adapt to + newtype. + * ast/rust-ast.cc (WhileLoopExpr::as_string): Likewise. + (LoopExpr::as_string): Likewise. + (BreakExpr::as_string): Likewise. + (ForLoopExpr::as_string): Likewise. + * ast/rust-expr.h (class BlockExpr): Make loop label optional. + (class BreakExpr): Likewise. + * expand/rust-derive-clone.cc (DeriveClone::clone_fn): Use nullopt. + * expand/rust-derive-debug.cc (DeriveDebug::stub_debug_fn): Likewise. + * expand/rust-derive-default.cc (DeriveDefault::default_fn): Likewise. + * expand/rust-derive-eq.cc: Likewise. + * parse/rust-parse-impl.h (Parser::parse_block_expr): Use optional + for arguments. + (Parser::parse_loop_expr): Likewise. + (Parser::parse_while_loop_expr): Likewise. + (Parser::parse_while_let_loop_expr): Likewise. + (Parser::parse_for_loop_expr): Likewise. + (Parser::parse_labelled_loop_expr): Likewise. + (Parser::parse_loop_label): Return an optional. + * parse/rust-parse.h: Update function prototype and use nullopt for + default values. + +2025-04-08 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * ast/rust-ast-visitor.cc (DefaultASTVisitor::visit): Change default + visit order. + +2025-04-08 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * ast/rust-ast-visitor.cc (DefaultASTVisitor::visit): Visit loop label + only if it exists. + +2025-04-08 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * hir/rust-ast-lower.cc (ASTLoweringBlock::visit): Lower label only if + it exists. + * hir/tree/rust-hir-expr.cc (BlockExpr::BlockExpr): Make loop label + optional. + (BaseLoopExpr::BaseLoopExpr): Likewise. + (LoopExpr::LoopExpr): Likewise. + (WhileLoopExpr::WhileLoopExpr): Likewise. + * hir/tree/rust-hir-expr.h: Use optional for lifetime and labels. + * hir/tree/rust-hir.cc (WhileLoopExpr::as_string): Use getter. + (WhileLetLoopExpr::as_string): Likewise. + (LoopExpr::as_string): Likewise. + * resolve/rust-late-name-resolver-2.0.cc (Late::visit): Resolve labels. + * resolve/rust-late-name-resolver-2.0.h: Add visit function prototype + for loop labels. + +2025-04-08 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * util/expected.h: Use gcc_unreachable within gcc context. + +2025-04-08 Sri Ganesh Thota <sriganeshthota12345@gmail.com> + + * resolve/rust-ast-resolve-base.h (redefined_error): created a function for + rust_error_at for redefined at multiple times. + * resolve/rust-ast-resolve-implitem.h: changed rust_error_at to redefined_error. + * resolve/rust-ast-resolve-stmt.cc (ResolveStmt::visit): changed rust_error_at to + redefined_error. + * resolve/rust-ast-resolve-stmt.h: changed rust_error_at to redefined_error. + * resolve/rust-ast-resolve-toplevel.h: changed rust_error_at to redefined_error. + +2025-04-08 Owen Avery <powerboat9.gamer@gmail.com> + + * ast/rust-ast-visitor.cc + (DefaultASTVisitor::visit): Remove explicit visitation of a + function's self parameter, as if it exists it'll be visited as + one of the function parameters. + +2025-04-08 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-typecheck-context.cc (TypeCheckContext::lookup_lifetime): emit error + +2025-04-08 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-ast.cc (Function::Function): Rename is_default -> has_default. + (Function::operator=): Likewise. + * ast/rust-item.h (class Function): Add `is_default` method. + * hir/rust-ast-lower-implitem.cc (ASTLowerImplItem::visit): Lower default qualifier. + * hir/rust-ast-lower-item.cc (ASTLoweringItem::visit): Likewise. + * hir/tree/rust-hir-item.cc (Function::Function): Add `is_default` member. + (Function::operator=): Likewise. + * hir/tree/rust-hir-item.h (enum class Defaultness): New enum. + (class Function): Use it. + +2025-04-08 Arthur Cohen <arthur.cohen@embecosm.com> + + * checks/errors/rust-feature.cc (Feature::create): Handle `#![feature(min_specialization)]`. + * checks/errors/rust-feature.h: Likewise. + +2025-04-08 Philip Herron <herron.philip@googlemail.com> + + * resolve/rust-ast-resolve-type.cc (ResolveRelativeTypePath::go): fix error msg + * typecheck/rust-substitution-mapper.cc (SubstMapper::Resolve): add validation + (SubstMapper::valid_type): new check + (SubstMapper::visit): check if can resolve + * typecheck/rust-substitution-mapper.h: new prototype + +2025-04-08 Philip Herron <herron.philip@googlemail.com> + + * backend/rust-compile-base.cc (HIRCompileBase::address_expression): allow optional type + * backend/rust-compile-base.h: update prototype + * backend/rust-compile-expr.cc (CompileExpr::visit): update borrow expr + * backend/rust-compile-extern.h: remove unused debug + * backend/rust-compile-resolve-path.cc (HIRCompileBase::query_compile): update usage + * hir/rust-ast-lower-expr.cc (ASTLoweringExpr::visit): lower raw ref + * hir/tree/rust-hir-expr.cc (BorrowExpr::BorrowExpr): add flag for raw ref + * hir/tree/rust-hir-expr.h (class BorrowExpr): add new raw ref field + * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit): add handle for raw ref + +2025-04-08 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-hir-type-check-pattern.cc (TypeCheckPattern::visit): emit error + +2025-04-08 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-hir-trait-resolve.cc (TraitResolver::resolve_trait): new argument + * typecheck/rust-hir-type-check-base.cc (TypeCheckBase::TypeCheckBase): new helper + * typecheck/rust-hir-type-check-base.h: new helper prototype + * typecheck/rust-hir-type-check-implitem.cc (TypeCheckTopLevelExternItem::visit): + remove comment out code + * typecheck/rust-hir-type-check-path.cc (TypeCheckExpr::resolve_root_path): check for null + * typecheck/rust-hir-type-check-type.cc (TypeCheckType::resolve_root_path): likewise + (TypeResolveGenericParam::Resolve): new args + (TypeResolveGenericParam::ApplyAnyTraitBounds): new helper + (TypeResolveGenericParam::apply_trait_bounds): new field + (TypeResolveGenericParam::visit): update + * typecheck/rust-hir-type-check-type.h: new args + * typecheck/rust-hir-type-check.cc (TraitItemReference::get_type_from_fn): reuse helper + * typecheck/rust-type-util.cc (query_type): check for recursive query + * typecheck/rust-tyty-subst.cc (SubstitutionParamMapping::SubstitutionParamMapping): + remove const + (SubstitutionParamMapping::get_generic_param): likewise + * typecheck/rust-tyty-subst.h: likewise + * typecheck/rust-tyty-variance-analysis.cc (GenericTyVisitorCtx::process_type): likewise + +2025-04-08 Philip Herron <herron.philip@googlemail.com> + + * backend/rust-compile-base.cc: new flag is_root_item + * backend/rust-compile-base.h: update prototype + * backend/rust-compile-implitem.cc (CompileTraitItem::visit): update call + * backend/rust-compile-implitem.h: remove old debug internal error + * backend/rust-compile-item.cc (CompileItem::visit): update call + * backend/rust-compile-item.h: remove old debug + * backend/rust-compile-resolve-path.cc (HIRCompileBase::query_compile): update calls + * backend/rust-compile.cc: likewise + * typecheck/rust-hir-trait-resolve.cc (TraitResolver::resolve_path_to_trait): + remove assertion and error + +2025-04-08 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-hir-type-check-base.cc: remove assertion + +2025-04-08 Philip Herron <herron.philip@googlemail.com> + + * rust-gcc.cc (arithmetic_or_logical_expression): unwrap const decls + +2025-04-08 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-forever-stack.h + (ForeverStack::ForeverStack): Initialize extern_prelude. + (ForeverStack::resolve_path): Add parameter + has_opening_scope_resolution. + (ForeverStack::extern_prelude): Add field. + * resolve/rust-forever-stack.hxx: Include rust-edition.h. + (ForeverStacl::resolve_path): Handle global paths (paths with an + opening scope resolution operator). + * resolve/rust-late-name-resolver-2.0.cc + (Late::visit): Handle global paths. + * resolve/rust-name-resolution-context.h + (NameResolutionContext::resolve_path): Handle global paths. + +2025-04-08 Ryutaro Okada <1015ryu88@gmail.com> + + * backend/rust-compile-resolve-path.cc: Evaluate the enum's discriminant in a const context + +2025-03-31 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-hir-type-check-type.cc (TypeCheckType::resolve_root_path): + catch nullptr root_tyty + +2025-03-31 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-hir-type-check-base.cc (TypeCheckBase::parse_repr_options): + check for null and empty and add missing delete call + +2025-03-31 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-tyty-subst.h: check for min range + +2025-03-31 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-hir-type-check-base.cc (TypeCheckBase::parse_repr_options): check for input + +2025-03-31 Philip Herron <herron.philip@googlemail.com> + + * hir/rust-hir-dump.cc (Dump::visit): check has type + * hir/tree/rust-hir-type.cc (BareFunctionType::BareFunctionType): likewise + +2025-03-31 Philip Herron <herron.philip@googlemail.com> + + * backend/rust-constexpr.cc (eval_store_expression): turn this back on + +2025-03-31 Owen Avery <powerboat9.gamer@gmail.com> + + * expand/rust-macro-builtins-log-debug.cc: + Add newline to end of file. + +2025-03-31 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-forever-stack.h + (ForeverStack::get_prelude): Rename to... + (ForeverStack::get_lang_prelude): ...here. + (ForeverStack::prelude): Rename to... + (ForeverStack::lang_prelude): ...here. + (ForeverStack::ForeverStack): Handle renames. + * resolve/rust-forever-stack.hxx + (ForeverStack::push_inner): Likewise. + (ForeverStack::resolve_segments): Likewise. + (ForeverStack::resolve_path): Likewise. + (ForeverStack::get_prelude): Rename to... + (ForeverStack::get_lang_prelude): ...here and handle renames. + * resolve/rust-late-name-resolver-2.0.cc + (Late::visit): Handle renames. + +2025-03-31 Philip Herron <herron.philip@googlemail.com> + + * backend/rust-compile-context.h: only push named types + * backend/rust-compile-type.cc (TyTyResolveCompile::visit): run the type hasher + +2025-03-31 Philip Herron <herron.philip@googlemail.com> + + * backend/rust-compile-resolve-path.cc (HIRCompileBase::query_compile): check for Expr trait + * hir/rust-hir-dump.cc (Dump::visit): expr is optional + +2025-03-31 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * resolve/rust-forever-stack.hxx: Add a new specialized function + to retrieve the last "real" segment depending on the namespace. + * resolve/rust-forever-stack.h: Add new function prototype. + * resolve/rust-early-name-resolver-2.0.cc (Early::finalize_rebind_import): + Set declared name according to the selected segment, if there is a self + suffix in the use declaration then select the previous segment. + +2025-03-31 Philip Herron <herron.philip@googlemail.com> + + * backend/rust-compile-base.cc (HIRCompileBase::unit_expression): pass ctx + * backend/rust-compile-base.h: cant be static + * backend/rust-compile-intrinsic.cc (try_handler_inner): pass ctx + * backend/rust-compile-type.cc + (TyTyResolveCompile::get_unit_type): update to grab the first locus + (TyTyResolveCompile::visit): pass ctx + * backend/rust-compile-type.h: likewise + +2025-03-31 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-hir-dot-operator.cc: + +2025-03-31 Philip Herron <herron.philip@googlemail.com> + + * resolve/rust-ast-resolve-path.cc (ResolvePath::resolve_path): check for super mid path + +2025-03-31 Philip Herron <herron.philip@googlemail.com> + + * backend/rust-compile-base.cc (HIRCompileBase::address_expression): new helper constexpr + * backend/rust-compile-base.h: prototype + * backend/rust-compile-type.cc (TyTyResolveCompile::visit): call constexpr helper + +2025-03-31 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-hir-type-check-item.cc (TypeCheckItem::resolve_impl_block_substitutions): + Track the polarity + * typecheck/rust-tyty-bounds.cc (TypeBoundPredicate::validate_type_implements_this): + new validator + * typecheck/rust-tyty.h: new prototypes + +2025-03-31 Philip Herron <herron.philip@googlemail.com> + + * backend/rust-compile-expr.cc (CompileExpr::array_value_expr): add value chk for array expr + +2025-03-31 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-hir-trait-reference.h: add default infer arg + * typecheck/rust-hir-trait-resolve.cc: dont add new infer vars + * typecheck/rust-hir-type-check-path.cc (TypeCheckExpr::resolve_segments): dont infer + +2025-03-31 Owen Avery <powerboat9.gamer@gmail.com> + + * checks/errors/rust-ast-validation.cc + (ASTValidation::visit): Allow constant items lacking expressions + if and only if they're associated with a trait definition, not a + trait implementation. + +2025-03-31 Owen Avery <powerboat9.gamer@gmail.com> + + * hir/rust-ast-lower-base.cc + (ASTLoweringBase::lower_literal): Lower raw string literals into + normal string literals. + +2025-03-31 Arthur Cohen <arthur.cohen@embecosm.com> + + * checks/errors/borrowck/ffi-polonius/Cargo.lock: Regenerate. + * checks/errors/borrowck/ffi-polonius/Cargo.toml: Update to use source patching instead of + vendoring, lower edition to 2018. + * checks/errors/borrowck/ffi-polonius/vendor/log/Cargo.toml: Change edition to 2018. + * checks/errors/borrowck/ffi-polonius/vendor/log/src/lib.rs: Remove uses of unstable + feature. + * checks/errors/borrowck/ffi-polonius/.cargo/config.toml: Removed. + +2025-03-31 Arthur Cohen <arthur.cohen@embecosm.com> + + * hir/tree/rust-hir-stmt.h (class LetStmt): Add optional diverging else expression. + * hir/tree/rust-hir-stmt.cc: Likewise. + * hir/rust-ast-lower-stmt.cc (ASTLoweringStmt::visit): Add handling for lowering + diverging else. + +2025-03-31 Arthur Cohen <arthur.cohen@embecosm.com> + + * resolve/rust-ast-resolve-stmt.h: Add handling for diverging else. + * resolve/rust-late-name-resolver-2.0.cc (Late::visit): Likewise. + +2025-03-31 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-ast-collector.cc (TokenCollector::visit): Add handling for diverging else + expression. + +2025-03-31 Arthur Cohen <arthur.cohen@embecosm.com> + + * parse/rust-parse-impl.h (Parser::parse_let_stmt): Add new parsing in case of `else` token. + +2025-03-31 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-stmt.h (class LetStmt): Add optional expression for diverging else. + * ast/rust-ast-builder.cc (Builder::let): Use new API. + +2025-03-26 Iain Sandoe <iain@sandoe.co.uk> + + * metadata/rust-export-metadata.cc + (PublicInterface::write_to_path): Use 'lbasename()' instead of + 'basename()'. + +2025-03-24 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-hir-path-probe.cc: update call + * typecheck/rust-hir-trait-reference.cc (TraitReference::lookup_trait_item): track predicate + (TraitReference::is_equal): likewise + (TraitReference::is_object_safe): likewise + (TraitReference::satisfies_bound): likewise + * typecheck/rust-hir-trait-reference.h: likewise + * typecheck/rust-hir-trait-resolve.cc (TraitResolver::resolve_trait): likewise + * typecheck/rust-tyty-bounds.cc (TypeBoundPredicate::TypeBoundPredicate): track super traits + (TypeBoundPredicate::operator=): likewise + (TypeBoundPredicate::apply_generic_arguments): ensure we apply to super predicates + (TypeBoundPredicateItem::operator=): take copy of parent predicate + (TypeBoundPredicateItem::error): pass error instead of nullptr + (TypeBoundPredicateItem::is_error): update to no longer check for nullptr + (TypeBoundPredicateItem::get_parent): updated + (TypeBoundPredicateItem::get_tyty_for_receiver): likewise + (TypeBoundPredicate::get_associated_type_items): likewise + * typecheck/rust-tyty-bounds.h (class TypeBoundPredicateItem): move + * typecheck/rust-tyty-subst.cc: flag to handle placeholder Self on traits + * typecheck/rust-tyty-subst.h (class TypeBoundPredicateItem): likewise + * typecheck/rust-tyty.h (class TypeBoundPredicateItem): refactored + +2025-03-24 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-late-name-resolver-2.0.cc + (Late::visit): Add visitor for StructExprFieldIdentifier. + * resolve/rust-late-name-resolver-2.0.h + (Late::visit): Likewise. + +2025-03-24 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-late-name-resolver-2.0.cc + (Late::visit): Make sure to return early after a resolution + error, improve the resolution error message, fix a typo, handle + ambiguous resolutions, and remove an old comment. + +2025-03-24 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-ast-resolve-expr.cc + (ResolveExpr::visit): Modify error message. + * resolve/rust-ast-resolve-implitem.h + (ResolveToplevelImplItem::visit): Likewise. + (ResolveTopLevelTraitItems::visit): Likewise. + (ResolveToplevelExternItem::visit): Likewise. + * resolve/rust-ast-resolve-stmt.cc + (ResolveStmt::visit): Likewise. + * resolve/rust-ast-resolve-stmt.h + (ResolveStmt::visit): Likewise. + * resolve/rust-ast-resolve-toplevel.h + (ResolveTopLevel::visit): Likewise. + * resolve/rust-ast-resolve-type.h + (ResolveGenericParams::visit): Likewise. + +2025-03-24 Owen Avery <powerboat9.gamer@gmail.com> + + * ast/rust-ast-visitor.cc + (DefaultASTVisitor::visit): Make sure to always visit the struct + name. + * resolve/rust-late-name-resolver-2.0.cc + (Late::visit): Avoid visiting the struct name twice. + +2025-03-24 Owen Avery <powerboat9.gamer@gmail.com> + + * expand/rust-derive-clone.cc + (DeriveClone::clone_impl): Avoid using the same node id multiple + times. + (DeriveClone::clone_enum_identifier): Likewise. + (DeriveClone::clone_enum_tuple): Likewise. + * expand/rust-derive-copy.cc + (DeriveCopy::copy_impl): Likewise. + * resolve/rust-ast-resolve-item.cc + (flatten_list): Likewise. + * resolve/rust-ast-resolve-path.cc + (ResolvePath::resolve_path): Prevent reinsertion of resolutions. + * resolve/rust-ast-resolve-type.cc + (ResolveRelativeTypePath::go): Likewise. + * typecheck/rust-hir-type-check-expr.cc + (TypeCheckExpr::resolve_fn_trait_call): Likewise. + * resolve/rust-name-resolver.cc + (Resolver::insert_resolved_name): Catch multiple resolution + insertions. + (Resolver::insert_resolved_type): Likewise. + +2025-03-24 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-ast-resolve-path.cc + (ResolvePath::resolve_path): Adjust the error message for a lower + self segment in the middle of a path. + * resolve/rust-ast-resolve-type.cc + (ResolveRelativeTypePath::go): Likewise. + +2025-03-24 Ryutaro Okada <1015ryu88@gmail.com> + + * typecheck/rust-hir-type-check-implitem.cc (TypeCheckTopLevelExternItem::visit): + emit an error for type or const parameters on foreign items + +2025-03-24 Liam Naddell <liamnprg@gmail.com> + + * resolve/rust-forever-stack.h (ForeverStack): Add a dedicated prelude node for + the Language prelude + * resolve/rust-forever-stack.hxx (ForeverStack): Add support code for the + prelude node + * resolve/rust-late-name-resolver-2.0.cc (Late::visit): Move + language prelude builtins to the prelude context + * resolve/rust-name-resolution-context.cc + (NameResolutionContext::scoped): Add code for handling + the prelude corner case + * resolve/rust-rib.h (Rib::Kind): Add a special Prelude rib type + +2025-03-24 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * resolve/rust-forever-stack.hxx: Fix the id comparison. + +2025-03-24 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * resolve/rust-forever-stack.hxx: Insert a new segment with the crate's + name as canonical's path prefix. + +2025-03-24 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * util/rust-hir-map.cc (Mappings::lookup_crate_num): Add function to + retrieve crate number from it's node id. + (Mappings::node_is_crate): change function with call to + lookup_crate_num to avoid looping through all crates. + (Mappings::insert_ast_crate): Populate node id to crate number map. + * util/rust-hir-map.h: Change function prototype. + +2025-03-24 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * resolve/rust-finalize-imports-2.0.cc (FinalizeImports::FinalizeImports): + Remove constructor. + (FinalizeImports::go): Remove function. + (FinalizeImports::visit): Likewise. + * resolve/rust-finalize-imports-2.0.h (class FinalizeImports): Remove + FinalizeImports class. + +2025-03-24 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * resolve/rust-early-name-resolver-2.0.cc (Early::Early): Move the + top level visitor from the function scope to attributes. + (Early::go): Remove top level visitor creation and adapt calling code. + Remove call to mapping resolution and import finalization. + (Early::finalize_simple_import): Move the finalization from it's + visitor. + (Early::finalize_glob_import): Likewise. + (Early::finalize_rebind_import): Likewise. + (Early::visit): Add mapping resolution and finalization in + UseDeclaration visitor function. + * resolve/rust-finalize-imports-2.0.cc (finalize_simple_import): Move + function. + (finalize_glob_import): Likewise. + (finalize_rebind_import): Likewise. + (FinalizeImports::visit): Remove call to finalizers. + * resolve/rust-early-name-resolver-2.0.h (class Early): Add top level + attribute. + * resolve/rust-finalize-imports-2.0.h: Add function prototypes. + * resolve/rust-toplevel-name-resolver-2.0.h: Change getter return type + to reference. + +2025-03-24 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-hir-trait-resolve.cc (TraitResolver::ResolveHirItem): new helper + * typecheck/rust-hir-trait-resolve.h: add helper prototype + * typecheck/rust-type-util.cc (query_type): add debug + * typecheck/rust-tyty-bounds.cc (TypeBoundsProbe::scan): check for recursion + * typecheck/rust-tyty.cc (VariantDef::is_equal): fix is equal check + +2025-03-24 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-hir-type-check-item.cc (TypeCheckItem::visit): track DefId of origin + * typecheck/rust-tyty.cc (BaseType::monomorphized_clone): likewise + (ADTType::ADTType): likewise + (ADTType::get_id): likewise + (ADTType::clone): likewise + * typecheck/rust-tyty.h: likewise + +2025-03-24 Philip Herron <herron.philip@googlemail.com> + + * backend/rust-compile-resolve-path.cc (ResolvePathRef::Compile): remove visitor + (ResolvePathRef::ResolvePathRef): likewise + (ResolvePathRef::visit): likewise + * backend/rust-compile-resolve-path.h (class ResolvePathRef): likewise + +2025-03-24 Owen Avery <powerboat9.gamer@gmail.com> + + * backend/rust-compile-intrinsic.cc + (assume_handler): Fix copy/paste error. + * typecheck/rust-hir-type-check-pattern.cc + (TypeCheckPattern::visit): Fix spelling mistake. + +2025-03-24 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * resolve/rust-rib.cc (Rib::Definition::to_string): Add enum variant + status. + +2025-03-24 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * resolve/rust-forever-stack.h: Add new function to insert enum + variants and add argument to resolver's get function to explicitely + skip enum variants. + * resolve/rust-forever-stack.hxx: Update function + definitions. + * resolve/rust-name-resolution-context.cc (NameResolutionContext::insert_variant): + Add function to insert enum variants. + * resolve/rust-name-resolution-context.h: Add function's prototype. + * resolve/rust-rib.cc (Rib::Definition::Definition): Add new boolean to + hint at enum variant provenance. + (Rib::Definition::is_variant): New getter for variant status. + (Rib::Definition::Shadowable): Update constructor to opt out of enum + variants. + (Rib::Definition::Globbed): Likewise. + (Rib::Definition::NonShadowable): Change constructor to forward enum + variant provenance status. + * resolve/rust-rib.h: Update function prototypes. + * resolve/rust-toplevel-name-resolver-2.0.cc (TopLevel::insert_enum_variant_or_error_out): + Add function to insert enum variants in the name resolver. + (TopLevel::visit): Update several enum variant's visitor function + with the new enum variant name resolving code. + * resolve/rust-toplevel-name-resolver-2.0.h: Update function + prototypes. + +2025-03-24 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * resolve/rust-forever-stack.hxx: Output rib kind. + * resolve/rust-rib.h: Add function to get string representation from + a rib kind. + +2025-03-24 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-forever-stack.h + (ForeverStack::ForeverStack): Set the node id of the root node + to that of the current crate. + * resolve/rust-forever-stack.hxx + (ForeverStack::find_starting_point): Use the node id of the root + node during resolution of crate segments. + +2025-03-24 Arthur Cohen <arthur.cohen@embecosm.com> + + * expand/rust-macro-expand.cc: Use new SubstituteCtx API. + * expand/rust-macro-expand.h: Likewise. + * expand/rust-macro-substitute-ctx.cc: Implement proper expansion of $crate. + * expand/rust-macro-substitute-ctx.h: Adapt APIs to take macro definition when + substituting. + * util/rust-hir-map.cc (Mappings::insert_macro_def): Store crate information when + inserting macro definition in mappings. + (Mappings::lookup_macro_def_crate): New. + * util/rust-hir-map.h: Adapt mappings to store crate in which macros were defined. + +2025-03-24 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-late-name-resolver-2.0.cc + (Late::visit): Call DefaultResolver::visit earlier, in order to + ensure it is called even if Late::visit returns early. + +2025-03-24 Owen Avery <powerboat9.gamer@gmail.com> + + * util/rust-edition.cc: New file. + * util/rust-edition.h: New file. + * Make-lang.in: Add rust-edition.o to the object list. + * ast/rust-pattern.cc: Remove inclusion of + rust-session-manager.h. + * expand/rust-macro-expand.cc: Likewise. + * expand/rust-macro-builtins-helpers.h: Likewise. + * expand/rust-macro-builtins-include.cc: Include + rust-session-manager.h. + * expand/rust-macro-builtins-utility.cc: Likewise. + * lex/rust-lex.cc: Include rust-edition.h instead of + rust-session-manager.h. + (Lexer::classify_keyword): Use get_rust_edition instead of + Session and CompileOptions. + * parse/rust-parse-impl.h: Include rust-edition.h instead of + rust-session-manager.h. + (Parser::parse_async_item): Use get_rust_edition instead of + Session and CompileOptions. + * checks/errors/rust-feature.h: Include rust-edition.h instead + of rust-session-manager.h. + (class Feature): Use Rust::Edition instead of + Rust::CompileOptions::Edition. + +2025-03-24 Arthur Cohen <arthur.cohen@embecosm.com> + + * rust-session-manager.cc (Session::compile_crate): Call DesugarQuestionMark::go(). + +2025-03-24 Arthur Cohen <arthur.cohen@embecosm.com> + + * hir/rust-ast-lower-base.cc: Adapt functions for ErrorPropagationExpr and MacroInvocation. + * hir/rust-ast-lower-base.h: Mark them as final. + * hir/rust-ast-lower-expr.cc: Remove previous definition for those overrides. + * hir/rust-ast-lower-expr.h: Likewise. + +2025-03-24 Arthur Cohen <arthur.cohen@embecosm.com> + + * Make-lang.in: Compile it. + * ast/rust-desugar-question-mark.cc: New file. + * ast/rust-desugar-question-mark.h: New file. + +2025-03-24 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-early-name-resolver-2.0.cc + (Early::visit): Adjust error produced when macro resolution + fails. + * resolve/rust-early-name-resolver.cc + (EarlyNameResolver::visit): Likewise. + +2025-03-24 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-forever-stack.hxx + (ForeverStack::find_starting_point): Stop when hitting a lang + item segment. + (ForeverStack::resolve_segments): Resolve lang item segments. + (ForeverStacl::resolve_path): Handle single segment lang item + paths and add comment. + * util/rust-unwrap-segment.cc + (unwrap_segment_get_lang_item): Add. + * util/rust-unwrap-segment.h + (unwrap_segment_get_lang_item): Add. + +2025-03-24 Arthur Cohen <arthur.cohen@embecosm.com> + + * expand/rust-expand-visitor.cc (ExpandVisitor::visit): Correctly visit the generic args + of a generic type path segment. + +2025-03-24 Arthur Cohen <arthur.cohen@embecosm.com> + + * resolve/rust-early-name-resolver.cc: Remove definitions. + * resolve/rust-early-name-resolver.h: Remove declarations. + +2025-03-24 Arthur Cohen <arthur.cohen@embecosm.com> + + * hir/rust-ast-lower-base.cc (ASTLoweringBase::visit): Add base implementation + for visitor. + +2025-03-24 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-early-name-resolver-2.0.cc: + Include rust-attribute-values.h. + (Early::visit): If a module has a macro_use attribute, avoid + pushing a new textual macro scope. + +2025-03-24 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-ast-resolve-type.cc + (ResolveRelativeTypePath::go): Adjust error message to match + the 2.0 name resolver. + +2025-03-24 Arthur Cohen <arthur.cohen@embecosm.com> + + * hir/rust-hir-dump.cc: Check unique_ptr members are present before + visiting them. + * hir/tree/rust-hir-path.h: Add `has_{type, trait}` methods to + QualifiedPathInType. + +2025-03-24 Arthur Cohen <arthur.cohen@embecosm.com> + + * Make-lang.in: Compile it. + * expand/rust-derive.cc (DeriveVisitor::derive): Call it. + * expand/rust-derive-hash.cc: New file. + * expand/rust-derive-hash.h: New file. + +2025-03-24 Arthur Cohen <arthur.cohen@embecosm.com> + + * expand/rust-derive-debug.cc (ptrify): Remove function. + +2025-03-24 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-ast-builder.cc (Builder::statementify): New. + (Builder::function): Add generic params optional argument. + (Builder::path_in_expression): Add opening_scope_resolution optional argument. + (Builder::block): Add function for creating empty blocks. + (Builder::generic_type_param): New. + * ast/rust-ast-builder.h (ptrify): New. + +2025-03-24 Owen Avery <powerboat9.gamer@gmail.com> + + * ast/rust-ast.h + (SingleASTNode::take_trait_item): Remove. + (SingleASTNode::take_impl_item): Remove. + (SingleASTNode::take_trait_impl_item): Remove. + * expand/rust-expand-visitor.cc + (ExpandVisitor::visit): Replace calls to aforementioned + functions with calls to SingleASTNode::take_assoc_item. + +2025-03-24 Owen Avery <powerboat9.gamer@gmail.com> + + * expand/rust-expand-visitor.cc + (ExpandVisitor::visit): Override DefaultASTVisitor in order to + expand a module's items, rather than directly visit them. + * expand/rust-expand-visitor.h + (ExpandVisitor::visit): Add override. + +2025-03-24 Owen Avery <powerboat9.gamer@gmail.com> + + * ast/rust-path.h + (PathInExpression::get_pattern_node_id): Remove. + +2025-03-24 Arthur Cohen <arthur.cohen@embecosm.com> + + * expand/rust-derive-eq.cc: Copy `Eq` typepath. + +2025-03-24 Arthur Cohen <arthur.cohen@embecosm.com> + + * expand/rust-derive-eq.cc: Adapt functions to return two generated impls. + * expand/rust-derive-eq.h: Likewise. + * expand/rust-derive.cc (DeriveVisitor::derive): Likewise. + +2025-03-24 Arthur Cohen <arthur.cohen@embecosm.com> + + * expand/rust-derive-partial-eq.cc: Adapt signatures to generate two impls. + * expand/rust-derive-partial-eq.h: Likewise. + * expand/rust-derive.cc (DeriveVisitor::derive): Adapt to multiple item generation. + +2025-03-24 Arthur Cohen <arthur.cohen@embecosm.com> + + * expand/rust-derive.cc (DeriveVisitor::derive): Return a vector of items. + * expand/rust-derive.h: Change return type. + * expand/rust-expand-visitor.cc: Insert all generated items into the AST. + +2025-03-24 Arthur Cohen <arthur.cohen@embecosm.com> + + * expand/rust-derive-partial-eq.cc: New file. + * expand/rust-derive-partial-eq.h: New file. + * expand/rust-derive.cc (DeriveVisitor::derive): Call them. + * Make-lang.in: Compile them. + +2025-03-24 Arthur Cohen <arthur.cohen@embecosm.com> + + * expand/rust-derive-clone.cc: Cleanup implementation, avoid repetitions. + * expand/rust-derive-clone.h: Likewise. + +2025-03-24 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-ast-builder.cc (Builder::literal_bool): New method. + (Builder::comparison_expr): Likewise. + (Builder::boolean_operation): Likewise. + * ast/rust-ast-builder.h: Declare them. + +2025-03-24 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-ast-builder.cc (Builder::block): Change return type. + (Builder::loop): Use new APIs. + * ast/rust-ast-builder.h: Change return type of block functions. + +2025-03-24 Arthur Cohen <arthur.cohen@embecosm.com> + + * expand/rust-derive.cc (DeriveVisitor::derive): Call into DeriveEq. + * expand/rust-derive-eq.cc: New file. + * expand/rust-derive-eq.h: New file. + * Make-lang.in: Compile them. + +2025-03-24 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-late-name-resolver-2.0.cc + (Late::visit): When visiting a PathInExpression instance, call + into DefaultResolver::visit, ensuring generic arguments are + visited. + +2025-03-24 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-toplevel-name-resolver-2.0.cc + (TopLevel::visit): When visiting an external crate declaration, + handle failed crate name lookups. This can happen when + Session::load_extern_crate fails to load a crate during the + CfgStrip phase. + +2025-03-24 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-forever-stack.hxx + (ForeverStack::resolve_segments): Add comments explaining + the behaviour of a while loop. + +2025-03-24 Benjamin Thos <benjamin.thos@epita.fr> + + * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit): + Add check on if-expr. + +2025-03-24 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-forever-stack.hxx + (ForeverStack::find_starting_point): Be more careful about + applying ForeverStack::find_closest_module. + (ForeverStack::resolve_segments): Allow traversal into parent + nodes when not in a module node or root node, which + ForeverStack::find_starting_point previously made moot through + use of ForeverStack::find_closest_module. Also, when a child + node lookup fails when resolving in the type namespace, attempt + a rib lookup as a fallback. + * resolve/rust-late-name-resolver-2.0.cc + (Late::visit): Avoid throwing a resolution error for type paths + when the typechecker may be able to finish the resolution. Also, + throw an error when a resolution is ambiguous. + +2025-03-24 Philip Herron <herron.philip@googlemail.com> + + * backend/rust-compile-type.cc (TyTyResolveCompile::visit): new tyty::OpaqueType + * backend/rust-compile-type.h: likewise + * checks/errors/borrowck/rust-bir-fact-collector.h: likewise + * checks/errors/borrowck/rust-bir-place.h: likewise + * checks/errors/privacy/rust-privacy-reporter.cc (PrivacyReporter::check_base_type_privacy): + likewise + * typecheck/rust-hir-type-check-type.cc (TypeCheckType::visit): likewise + * typecheck/rust-hir-type-check-type.h: likewise + * typecheck/rust-substitution-mapper.cc (SubstMapperInternal::visit): likewise + * typecheck/rust-substitution-mapper.h: likewise + * typecheck/rust-tyty-bounds.cc (TypeBoundsProbe::assemble_sized_builtin): likewise + * typecheck/rust-tyty-call.h: likewise + * typecheck/rust-tyty-cmp.h (class OpaqueCmp): likewise + * typecheck/rust-tyty-variance-analysis-private.h: likewise + * typecheck/rust-tyty-visitor.h: likewise + * typecheck/rust-tyty.cc (TypeKindFormat::to_string): likewise + (BaseType::is_unit): likewise + (BaseType::destructure): likewise + (BaseType::has_substitutions_defined): likewise + (BaseType::needs_generic_substitutions): likewise + (OpaqueType::OpaqueType): likewise + (OpaqueType::can_resolve): likewise + (OpaqueType::accept_vis): likewise + (OpaqueType::as_string): likewise + (OpaqueType::get_name): likewise + (OpaqueType::can_eq): likewise + (OpaqueType::clone): likewise + (OpaqueType::resolve): likewise + (OpaqueType::is_equal): likewise + (OpaqueType::handle_substitions): likewise + * typecheck/rust-tyty.h (enum TypeKind): likewise + (class OpaqueType): likewise + * typecheck/rust-unify.cc (UnifyRules::go): likewise + (UnifyRules::expect_inference_variable): likewise + (UnifyRules::expect_adt): likewise + (UnifyRules::expect_str): likewise + (UnifyRules::expect_reference): likewise + (UnifyRules::expect_pointer): likewise + (UnifyRules::expect_param): likewise + (UnifyRules::expect_array): likewise + (UnifyRules::expect_slice): likewise + (UnifyRules::expect_fndef): likewise + (UnifyRules::expect_fnptr): likewise + (UnifyRules::expect_tuple): likewise + (UnifyRules::expect_bool): likewise + (UnifyRules::expect_char): likewise + (UnifyRules::expect_int): likewise + (UnifyRules::expect_uint): likewise + (UnifyRules::expect_float): likewise + (UnifyRules::expect_isize): likewise + (UnifyRules::expect_usize): likewise + (UnifyRules::expect_placeholder): likewise + (UnifyRules::expect_projection): likewise + (UnifyRules::expect_dyn): likewise + (UnifyRules::expect_opaque): likewise + * typecheck/rust-unify.h: likewise + +2025-03-24 Philip Herron <herron.philip@googlemail.com> + + * checks/errors/borrowck/rust-bir-builder-struct.h: remove HIR::ImplTraitTypeOneBound + * checks/errors/borrowck/rust-function-collector.h: likewise + * checks/errors/rust-const-checker.cc (ConstChecker::visit): likewise + * checks/errors/rust-const-checker.h: likewise + * checks/errors/rust-hir-pattern-analysis.cc (PatternChecker::visit): likewise + * checks/errors/rust-hir-pattern-analysis.h: likewise + * checks/errors/rust-unsafe-checker.cc (UnsafeChecker::visit): likewise + * checks/errors/rust-unsafe-checker.h: likewise + * hir/rust-ast-lower-type.cc (ASTLoweringType::translate): likewise + (ASTLoweringType::visit): likewise + * hir/rust-ast-lower-type.h: cleanup + * hir/rust-hir-dump.cc (Dump::visit): remove ImplTraitTypeOneBound + * hir/rust-hir-dump.h: likewise + * hir/tree/rust-hir-full-decls.h (class ImplTraitTypeOneBound): likewise + * hir/tree/rust-hir-type.h (class ImplTraitTypeOneBound): likewise + * hir/tree/rust-hir-visitor.h: likewise + * hir/tree/rust-hir.cc (ImplTraitTypeOneBound::as_string): likewise + (ImplTraitTypeOneBound::accept_vis): likewise + * resolve/rust-ast-resolve-type.cc (ResolveType::go): likewise + (ResolveType::visit): likewise + * resolve/rust-ast-resolve-type.h: add name resolution + * typecheck/rust-hir-type-check-type.h: likewise + +2025-03-24 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit): improve error diag + +2025-03-24 Philip Herron <herron.philip@googlemail.com> + + * hir/rust-ast-lower-base.cc (ASTLoweringBase::lower_self): add location mappings + * typecheck/rust-hir-type-check-path.cc (TypeCheckExpr::resolve_root_path): check for self + +2025-03-24 Philip Herron <herron.philip@googlemail.com> + + * resolve/rust-ast-resolve-item.cc (ResolveTraitItems::visit): use new api + (ResolveItem::visit): likewise + (ResolveExternItem::visit): likewise + * resolve/rust-ast-resolve-stmt.h: likewise + * resolve/rust-ast-resolve-type.h (class ResolveGenericParam): remove + (class ResolveGenericParams): added new api + +2025-03-24 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-hir-type-check-base.cc (walk_types_to_constrain): recursive walker + * typecheck/rust-tyty.cc (BaseType::get_subst_argument_mappings): new helper + * typecheck/rust-tyty.h: prototype + +2025-03-24 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-hir-type-check-base.h: add flag + * typecheck/rust-hir-type-check-type.cc (TypeCheckType::visit): likewise + * typecheck/rust-tyty-bounds.cc: new diagnostic + +2025-03-24 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-hir-type-check-type.cc (TypeCheckType::visit): remove name resolution info + (TypeCheckType::resolve_root_path): likewise + * typecheck/rust-hir-type-check-type.h: likewise + +2025-03-24 Philip Herron <herron.philip@googlemail.com> + + * backend/rust-compile-type.cc (TyTyResolveCompile::get_implicit_enumeral_node_type): + use repr + (TyTyResolveCompile::visit): update prototype + * backend/rust-compile-type.h: likewise + +2025-03-24 Philip Herron <herron.philip@googlemail.com> + + * backend/rust-compile-intrinsic.cc (variant_count_handler): new intrinsic + +2025-03-24 Philip Herron <herron.philip@googlemail.com> + + * backend/rust-compile-intrinsic.cc (discriminant_value_handler): new handler + * typecheck/rust-hir-trait-resolve.cc (TraitItemReference::resolve_item): track the defid + * typecheck/rust-hir-type-check-base.cc (TypeCheckBase::parse_repr_options): default isize + * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit): special case CallExpr + * typecheck/rust-hir-type-check-item.cc (TypeCheckItem::visit): parse repr options enum + * typecheck/rust-hir-type-check-type.cc (TypeCheckType::visit): remove bad diagnostic + * typecheck/rust-tyty.cc (PlaceholderType::PlaceholderType): track defid + (PlaceholderType::clone): likewise + (PlaceholderType::get_def_id): likeiwse + * typecheck/rust-tyty.h: placeholder track defid + * util/rust-lang-item.cc: add new lang items + * util/rust-lang-item.h: likewise + +2025-03-24 GS-GOAT <86884129+GS-GOAT@users.noreply.github.com> + + * typecheck/rust-autoderef.cc + (insert_implicit_type): Update single-parameter call to + pass explicit HirId. + * typecheck/rust-hir-type-check-expr.cc: Same. + * typecheck/rust-hir-type-check-pattern.cc: Same. + * typecheck/rust-hir-type-check.h: Removed call + to the duplicate interface. + * typecheck/rust-typecheck-context.cc + (TypeCheckContext::insert_implicit_type): Removed the + interface with no HirId field. + +2025-03-24 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-tyty-subst.cc (SubstitutionRef::monomorphize): remove diagnostic + +2025-03-24 Arthur Cohen <arthur.cohen@embecosm.com> + + * rust-session-manager.cc (Session::compile_crate): Call the visitor. + +2025-03-24 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-desugar-for-loops.cc: New file. + * ast/rust-desugar-for-loops.h: New file. + * hir/rust-ast-lower-expr.cc (ASTLoweringExpr::visit): Make lowering of for-loops an + unreachable. + * Make-lang.in: Compile it. + +2025-03-24 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-ast-builder.h: Mark all arguments as &&. + * ast/rust-ast-builder.cc (Builder::let): Likewise. + +2025-03-24 Owen Avery <powerboat9.gamer@gmail.com> + + * util/rust-unwrap-segment.cc: New file. + * util/rust-unwrap-segment.h: New file. + * Make-lang.in: Add rust-unwrap-segment.o to the object list. + * resolve/rust-forever-stack.hxx: Include rust-unwrap-segment.h. + (ForeverStack::find_starting_point): Use unwrap_type_segment. + (ForeverStack::resolve_segments): Likewise. + (ForeverStack::resolve_path): Likewise. + * resolve/rust-late-name-resolver-2.0.cc + (Late::visit): Resolve type paths using + NameResolutionContext::resolve_path. + * resolve/rust-name-resolution-context.h + (NameResolutionContext::resolve_path): Use + unwrap_segment_node_id. + +2025-03-24 Arthur Cohen <arthur.cohen@embecosm.com> + + * expand/rust-macro-builtins-asm.cc (strip_double_quotes): Special case empty + strings ("\"\""). + (parse_reg_operand): Remove use of the `struct` keyword. + (parse_reg_operand_in): Likewise. + (parse_reg_operand_out): Likewise. + * expand/rust-macro-builtins.cc: Add llvm_asm! built-in macro as an alias to asm!. + +2025-03-24 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * resolve/rust-toplevel-name-resolver-2.0.cc (TopLevel::visit): Add + warning about current code. + +2025-03-24 Arthur Cohen <arthur.cohen@embecosm.com> + + * expand/rust-derive.cc (DeriveVisitor::derive): Call DeriveDefault. + * expand/rust-derive-default.cc: New file. + * expand/rust-derive-default.h: New file. + * Make-lang.in: Compile them. + +2025-03-24 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-ast-builder.cc (Builder::qualified_path_in_expression): New. + (Builder::function): Change the return type. + * ast/rust-ast-builder.h: Declare qualified_path_in_expression functions. + * expand/rust-derive-debug.cc (DeriveDebug::stub_debug_fn): Adapt to new APIs. + +2025-03-24 Philip Herron <herron.philip@googlemail.com> + + * backend/rust-compile-expr.cc (CompileExpr::visit): remove receiver interface + * backend/rust-compile-item.cc (CompileItem::visit): monomorphize trait to impl item + * backend/rust-compile-resolve-path.cc (HIRCompileBase::query_compile): use trait item Self + * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit): remove receiver interface + (TypeCheckExpr::resolve_fn_trait_call): likewise + * typecheck/rust-hir-type-check-path.cc (TypeCheckExpr::visit): likewise + (TypeCheckExpr::resolve_segments): likewise + * typecheck/rust-hir-type-check-type.cc (TypeCheckType::visit): likewise + * typecheck/rust-hir-type-check.h: likewise + * typecheck/rust-typecheck-context.cc (TypeCheckContext::insert_receiver): remove + (TypeCheckContext::lookup_receiver): remove + +2025-03-24 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-substitution-mapper.cc (SubstMapperInternal::visit): + continue on for trait item mode. + +2025-03-24 Philip Herron <herron.philip@googlemail.com> + + * checks/errors/privacy/rust-privacy-reporter.cc (PrivacyReporter::check_base_type_privacy): + Add guard for placeholder + +2025-03-24 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-type-util.cc (coercion_site): allow inference vars + +2025-03-24 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-hir-path-probe.cc (PathProbeType::visit): remove assertion + +2025-03-24 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-tyty.cc (ClosureType::setup_fn_once_output): add checks for lang items + +2025-03-24 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-early-name-resolver-2.0.cc + (Early::resolve_glob_import): Use + NameResolutionContext::resolve_path instead of + ForeverStack::resolve_path. + (Early::visit): Likewise. + (Early::visit_attributes): Likewise. + * resolve/rust-early-name-resolver-2.0.h + (Early::resolve_path_in_all_ns): Likewise. + * resolve/rust-late-name-resolver-2.0.cc + (Late::visit): Likewise, insert segment resolutions not + handled by NameResolutionContext::resolve_path, and avoid throwing + an error when path resolution could be finished by the typechecker. + * resolve/rust-name-resolution-context.h + (NameResolutionContext::resolve_path): Add. + * typecheck/rust-hir-type-check-path.cc + (TypeCheckExpr::resolve_root_path): Use segment node ids instead + of the path node id to look up segment resolutions when using + the 2.0 resolver, as is done with the 1.0 resolver. + * typecheck/rust-hir-type-check-type.cc + (TypeCheckType::resolve_root_path): Likewise. + * resolve/rust-forever-stack.h + (ForeverStack::resolve_path): Add callback parameter for + inserting segment resolutions. + (ForeverStack::find_starting_point): Likewise. + (ForeverStack::resolve_segments): Likewise. + * resolve/rust-forever-stack.hxx + (ForeverStack::find_starting_point): Likewise. + (ForeverStack::resolve_segments): Likewise. + (ForeverStack::resolve_path): Likewise and avoid resolving + inside TraitOrImpl ribs. + +2025-03-24 Owen Avery <powerboat9.gamer@gmail.com> + + * backend/rust-compile-expr.cc + (CompileExpr::generate_closure_function): Take + NameResolutionContext by reference instead of by value. + * backend/rust-compile-item.cc + (CompileItem::visit): Likewise. + * backend/rust-compile-resolve-path.cc + (ResolvePathRef::resolve): Likewise. + * checks/lints/rust-lint-marklive.cc + (MarkLive::find_ref_node_id): Likewise. + * typecheck/rust-hir-type-check-enumitem.cc + (TypeCheckEnumItem::visit): Likewise. + * typecheck/rust-hir-type-check-implitem.cc + (TypeCheckImplItem::visit): Likewise. + * typecheck/rust-hir-type-check-item.cc + (TypeCheckItem::visit): Likewise. + * typecheck/rust-hir-type-check-path.cc + (TypeCheckExpr::resolve_root_path): Likewise. + * typecheck/rust-hir-type-check-type.cc + (TypeCheckType::resolve_root_path): Likewise. + +2025-03-24 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-ast-builder.h: Declare it. + * ast/rust-ast-builder.cc (Builder::return_expr): Define it. + +2025-03-24 Arthur Cohen <arthur.cohen@embecosm.com> + + * expand/rust-derive-debug.cc: New file. + * expand/rust-derive-debug.h: New file. + * Make-lang.in: Compile them. + * expand/rust-derive.cc (DeriveVisitor::derive): Call into DeriveDebug. + +2025-03-24 Arthur Cohen <arthur.cohen@embecosm.com> + + * expand/rust-derive-clone.cc: Cleanup using DeriveVisitor::setup_impl_generics. + * expand/rust-derive-copy.cc: Likewise. + +2025-03-24 Arthur Cohen <arthur.cohen@embecosm.com> + + * expand/rust-derive.cc (DeriveVisitor::setup_impl_generics): New method. + * expand/rust-derive.h: Declare it, define DeriveVisitor::ImplGenerics struct. + +2025-03-24 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-ast-builder.cc: New methods. + * ast/rust-ast-builder.h: Declare them. + +2025-03-24 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-ast-builder.cc (Builder::type_path): New functions. + * ast/rust-ast-builder.h: Declare them. + +2025-03-24 Arthur Cohen <arthur.cohen@embecosm.com> + + * checks/lints/rust-lint-scan-deadcode.h: Check if the field name starts with an + underscore before warning. + +2025-03-24 Arthur Cohen <arthur.cohen@embecosm.com> + + * util/rust-lang-item.cc: New items. + * util/rust-lang-item.h: Likewise. + +2025-03-24 Arthur Cohen <arthur.cohen@embecosm.com> + + * resolve/rust-late-name-resolver-2.0.cc (Late::visit): Special case lang item paths. + +2025-03-24 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-forever-stack.hxx + (ForeverStack::dfs_rib): Fix const implementation. + +2025-03-24 Liam Naddell <liamnprg@gmail.com> + + * expand/rust-macro-builtins-utility.cc: Add macro expansion for + option_env with eager expansion + * expand/rust-macro-builtins.cc: Add option_env to builtin list + * expand/rust-macro-builtins.h: Add option_env handler to header + file + * resolve/rust-late-name-resolver-2.0.cc: Prevent NR2.0 from + recursing into lang-item segments + +2025-03-24 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-ast.h: Add new Expr::Kinds. + * ast/rust-expr.h: Implement missing get_expr_kind(), Add get_function_expr_ptr() + +2025-03-24 Philip Herron <herron.philip@googlemail.com> + + * backend/rust-compile-pattern.cc (CompilePatternBindings::visit): make recursive + * typecheck/rust-hir-type-check-pattern.cc (TypeCheckPattern::visit): handle ref flag + +2025-03-24 Arthur Cohen <arthur.cohen@embecosm.com> + + * util/rust-lang-item.h: Declare it. + * util/rust-lang-item.cc: Use it. + +2025-03-24 Philip Herron <herron.philip@googlemail.com> + + * backend/rust-compile-expr.cc (CompileExpr::visit): disable overflow checks + * lang.opt: new flag + +2025-03-24 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * backend/rust-compile-resolve-path.cc (ResolvePathRef::resolve): Do + not use query system for unit struct but compile it's constructor + instead. + +2025-03-24 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * typecheck/rust-hir-trait-resolve.cc (TraitResolver::resolve_path_to_trait): + Query all namespaces. + +2025-03-24 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * resolve/rust-forever-stack.h: Make debug functions const. + * resolve/rust-forever-stack.hxx: Likewise. + +2025-03-24 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * typecheck/rust-hir-type-check-enumitem.cc (TypeCheckEnumItem::visit): + Clone expr instead of taking it. + +2025-03-24 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * backend/rust-compile-item.h: Remove query mode. + * backend/rust-compile-resolve-path.cc (HIRCompileBase::query_compile): + Likewise. + +2025-03-24 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * resolve/rust-ast-resolve-toplevel.h: Add struct to name namespace. + +2025-03-24 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * resolve/rust-name-resolver.h: Add new degug dump for old name + resolver. + +2025-03-24 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * resolve/rust-ast-resolve-expr.cc (ResolveExpr::visit): Change label + push function from type rib to label rib. + * resolve/rust-ast-resolve-item.cc (ResolveTraitItems::visit): + Likewise. + (ResolveItem::visit): Likewise. + (ResolveExternItem::visit): Likewise. + * resolve/rust-ast-resolve-stmt.h: Likewise. + * resolve/rust-ast-resolve.cc (NameResolution::go): Likewise. + +2025-03-24 Arthur Cohen <arthur.cohen@embecosm.com> + + * backend/rust-compile-resolve-path.cc (ResolvePathRef::visit): Call into + resolve_path_like instead. + (ResolvePathRef::resolve_path_like): New. + (ResolvePathRef::resolve): Call into resolve_with_node_id. + * backend/rust-compile-resolve-path.h: Declare new functions and document them. + +2025-03-24 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-path.h: New function. + +2025-03-24 Arthur Cohen <arthur.cohen@embecosm.com> + + * checks/lints/rust-lint-marklive.cc (MarkLive::visit): Adapt to lang items. + +2025-03-24 Arthur Cohen <arthur.cohen@embecosm.com> + + * backend/rust-compile-resolve-path.cc (ResolvePathRef::visit): Adapt visitor to lang item + HIR::PathInExpressions. + * typecheck/rust-hir-type-check-path.cc (TypeCheckExpr::visit): Likewise. + +2025-03-24 Arthur Cohen <arthur.cohen@embecosm.com> + + * hir/tree/rust-hir-path.h: Adapt PathPattern to accept lang-item paths. + * hir/tree/rust-hir-path.cc: Assert we are dealing with a segmented path, create lang-item + constructors. + * hir/tree/rust-hir.cc (PathPattern::convert_to_simple_path): Likewise. + +2025-03-24 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-ast-collector.cc (TokenCollector::visit): Adapt visitor to lang item + PathInExpressions. + * ast/rust-ast-visitor.cc (DefaultASTVisitor::visit): Likewise. + * expand/rust-cfg-strip.cc (CfgStrip::visit): Likewise. + * expand/rust-expand-visitor.cc (ExpandVisitor::visit): Likewise. + * hir/rust-ast-lower.cc (ASTLoweringExprWithBlock::visit): Likewise. + (ASTLowerPathInExpression::visit): Likewise. + * resolve/rust-ast-resolve-path.cc (ResolvePath::resolve_path): Likewise. + * resolve/rust-early-name-resolver.cc (EarlyNameResolver::visit): Likewise. + +2025-03-24 Arthur Cohen <arthur.cohen@embecosm.com> + + * util/rust-lang-item.cc (LangItem::IsEnumVariant): New function. + * util/rust-lang-item.h: Declare it. + +2025-03-24 Arthur Cohen <arthur.cohen@embecosm.com> + + * util/rust-hir-map.cc (Mappings::get_lang_item_node): Better formatting when a lang + item does not exist when it should. + +2025-03-24 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-collect-lang-items.h: Declare visitor. + * ast/rust-collect-lang-items.cc (CollectLangItems::visit): New. + +2025-03-24 Philip Herron <herron.philip@googlemail.com> + + * backend/rust-compile-resolve-path.cc (HIRCompileBase::query_compile): add guard + +2025-03-24 Dylan Gardner <dylan@gardnermedia.com> + + * rust-session-manager.cc (Session::handle_crate_name): Remove + crate name inference + (Session::compile_crate): Add crate name inference and error if + inferred name is empty. Remove CompileOptions::get_instance () + that returned a local copy of the options. Rename + crate_name_changed to crate_name_found to match semantics. + (rust_crate_name_validation_test): Test inferring ".rs" name + * rust-session-manager.h: Modify handle_crate_name definition to + include filename. + +2025-03-24 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * resolve/rust-late-name-resolver-2.0.cc (Late::visit): Add + ClosureExprInnerTyped visit implementation. + (add_captures): Add a function to avoid code duplication. + * resolve/rust-late-name-resolver-2.0.h: Add function prototype. + +2025-03-24 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * resolve/rust-late-name-resolver-2.0.cc (Late::visit): Add environment + collection. + * resolve/rust-late-name-resolver-2.0.h: Add function prototype. + * resolve/rust-name-resolver.cc (Resolver::get_captures): Add assertion + to prevent NR2 usage with nr1 capture functions. + * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit): Use + nr2 captures. + * util/rust-hir-map.cc (Mappings::add_capture): Add function to + register capture for a given closure. + (Mappings::lookup_captures): Add a function to lookup all captures + available for a given closure. + * util/rust-hir-map.h: Add function prototypes. + +2025-03-24 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-late-name-resolver-2.0.cc + (Late::visit): Error out if a type path has multiple segments, + as we currently ignore every segment except the last. + +2025-03-24 Arthur Cohen <arthur.cohen@embecosm.com> + + * backend/rust-compile-expr.cc (check_match_scrutinee): Allow anything to be used as a + match scrutinee, not just ADTs. + +2025-03-24 Arthur Cohen <arthur.cohen@embecosm.com> + + * util/rust-lang-item.h: Add handling for Result::Ok, Result::Err, Try, Try::into_result, + Try::from_ok, Try::from_err. + * util/rust-lang-item.cc: Likewise. + +2025-03-24 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * resolve/rust-late-name-resolver-2.0.cc (Late::visit): Add "rust" + identifier detection akin to nr1. + (funny_ice_finalizer): Copy ICE finalizer from nr1. + * resolve/rust-late-name-resolver-2.0.h: Add funny_error member + context state. + * Make-lang.in: Add new translation unit for new ice finalizer. + * resolve/rust-ast-resolve-expr.cc: Move ice + finalizer to it's own file. + * resolve/rust-ice-finalizer.cc: New file. + * resolve/rust-ice-finalizer.h: New file. + +2025-03-24 Arthur Cohen <arthur.cohen@embecosm.com> + + * expand/rust-derive-copy.cc: Always add an extra Copy bound on generic Copy impls. + +2025-03-24 Arthur Cohen <arthur.cohen@embecosm.com> + + * expand/rust-derive-clone.cc (DeriveClone::visit_union): Use lang items for Copy and + Sized bounds. + +2025-03-24 Arthur Cohen <arthur.cohen@embecosm.com> + + * expand/rust-derive-clone.cc: Add extra bound when deriving generic Clone + +2025-03-24 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-ast-builder.cc (Builder::new_type_param): Add optional extra trait bounds. + * ast/rust-ast-builder.h: Likewise. + +2025-03-24 Arthur Cohen <arthur.cohen@embecosm.com> + + * hir/rust-hir-dump.cc (Dump::do_typepathsegment): Add handling for lang items. + +2025-03-24 lishin <lishin1008@gmail.com> + + * util/rust-lang-item.cc: Add receiver to map. + * util/rust-lang-item.h: Define LangItem::Kind::RECEIVER. + +2025-03-24 Arthur Cohen <arthur.cohen@embecosm.com> + + * hir/rust-ast-lower-item.cc (ASTLoweringItem::visit): Register auto traits in mappings. + * util/rust-hir-map.cc (Mappings::insert_auto_trait): New. + (Mappings::get_auto_traits): New. + * util/rust-hir-map.h: Declare them. + * typecheck/rust-tyty-bounds.cc (TypeBoundsProbe::scan): Add auto trait bounds when + scanning. + +2025-03-24 Arthur Cohen <arthur.cohen@embecosm.com> + + * typecheck/rust-tyty-bounds.cc (TypeBoundsProbe::add_trait_bound): New function. + * typecheck/rust-hir-type-bounds.h: Declare it. + (TypeBoundsProbe::assemble_builtin_candidate): Call into add_trait_bound. + +2025-03-21 Arthur Cohen <arthur.cohen@embecosm.com> + + * resolve/rust-late-name-resolver-2.0.cc (Late::visit): Improve formatting. + +2025-03-21 Arthur Cohen <arthur.cohen@embecosm.com> + + * expand/rust-derive-clone.cc (DeriveClone::clone_enum_struct): New function for deriving + enum struct variants. + (DeriveClone::visit_enum): Call into the new function. + +2025-03-21 Arthur Cohen <arthur.cohen@embecosm.com> + + * expand/rust-derive-clone.cc (DeriveClone::variant_match_path): New function. + (DeriveClone::clone_enum_identifier): Rename. + (DeriveClone::clone_enum_tuple): New function. + (DeriveClone::visit_enum): Visit tuple variants properly. + * expand/rust-derive-clone.h: Declare new functions. + +2025-03-21 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-ast-builder.cc: Add new methods for constructing struct exprs. + * ast/rust-ast-builder.h: Mention how to build tuple expressions. + +2025-03-21 Arthur Cohen <arthur.cohen@embecosm.com> + + * expand/rust-derive-clone.cc: Clone enum identifier variants properly + * expand/rust-derive-clone.h: Declare new functions used. + +2025-03-21 Arthur Cohen <arthur.cohen@embecosm.com> + + * expand/rust-derive-clone.cc (DeriveClone::clone_call): Mention using `clone_fn` + lang item in the future. + +2025-03-21 Arthur Cohen <arthur.cohen@embecosm.com> + + * expand/rust-derive-clone.cc (DeriveClone::visit_union): Create a lang item path + instead of a regular path. + +2025-03-21 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-ast-builder.cc: New functions. + * ast/rust-ast-builder.h: Declare them. + +2025-03-21 Arthur Cohen <arthur.cohen@embecosm.com> + + * expand/rust-derive-copy.cc: Use lang item path. + +2025-03-21 Arthur Cohen <arthur.cohen@embecosm.com> + + * expand/rust-derive-clone.cc (DeriveClone::visit_union): Manually generate + the struct used for asserting a union implements Copy. + +2025-03-21 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-ast-builder.cc (Builder::struct_struct): New function. + * ast/rust-ast-builder.h (vec): New function. + +2025-03-21 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-ast-collector.cc (TokenCollector::visit): Visit tuple pattern items as + separated by commas. + +2025-03-21 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-ast-collector.cc (TokenCollector::visit): Fix collector to better + handle lang item type path segments. + +2025-03-21 Arthur Cohen <arthur.cohen@embecosm.com> + + * util/rust-hir-map.cc (Mappings::get_lang_item_node): New. + * util/rust-hir-map.h: New function. + +2025-03-21 Arthur Cohen <arthur.cohen@embecosm.com> + + * util/rust-lang-item.cc (LangItem::PrettyString): New. + * util/rust-lang-item.h: New. + +2025-03-21 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-collect-lang-items.cc (CollectLangItems::visit): New. + * ast/rust-collect-lang-items.h: New. + +2025-03-21 Arthur Cohen <arthur.cohen@embecosm.com> + + * hir/rust-ast-lower-type.cc (ASTLowerTypePath::visit): Adapt code to lang item + type path segments. + +2025-03-21 Arthur Cohen <arthur.cohen@embecosm.com> + + * typecheck/rust-hir-type-check-type.cc (TypeCheckType::resolve_root_path): Adapt + code to handle lang item type paths. + +2025-03-21 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-path.h: Rework how lang item paths are represented. + * ast/rust-path.cc: Likewise. + * ast/rust-item.h: Likewise. + * ast/rust-ast.cc: Likewise. + * ast/rust-ast-collector.cc: Adapt to new lang item path system. + * ast/rust-ast-collector.h: Likewise. + * ast/rust-ast-visitor.cc (DefaultASTVisitor::visit): Likewise. + * ast/rust-ast-visitor.h: Likewise. + * expand/rust-derive-copy.cc: Likewise. + * expand/rust-derive.h: Likewise. + * hir/rust-ast-lower-base.cc (ASTLoweringBase::visit): Likewise. + * hir/rust-ast-lower-base.h: Likewise. + * hir/rust-ast-lower-type.cc (ASTLowerTypePath::translate): Likewise. + (ASTLowerTypePath::visit): Likewise. + * hir/rust-ast-lower-type.h: Likewise. + * resolve/rust-ast-resolve-base.cc (ResolverBase::visit): Likewise. + * resolve/rust-ast-resolve-base.h: Likewise. + * resolve/rust-ast-resolve-item.cc (ResolveItem::visit): Likewise. + * resolve/rust-ast-resolve-type.h: Likewise. + * resolve/rust-ast-resolve-type.cc (ResolveRelativeTypePath::go): Likewise. + * resolve/rust-late-name-resolver-2.0.cc (Late::visit): Likewise. + * resolve/rust-late-name-resolver-2.0.h: Likewise. + * hir/tree/rust-hir-path.cc (TypePathSegment::TypePathSegment): Likewise. + (TypePathSegmentGeneric::TypePathSegmentGeneric): Likewise. + * hir/tree/rust-hir-path.h: Likewise. + * typecheck/rust-hir-type-check-type.cc (TypeCheckType::resolve_root_path): Likewise. + * ast/rust-ast-builder.cc: Likewise. + * ast/rust-ast-builder.h: Likewise. + +2025-03-21 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-collect-lang-items.cc (get_lang_item_attr): Show unknown attribute upon error. + +2025-03-21 Arthur Cohen <arthur.cohen@embecosm.com> + + * util/rust-attribute-values.h: Declare new attribute value. + * util/rust-attributes.cc: Use it. + +2025-03-21 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-ast.cc (BlockExpr::normalize_tail_expr): Remove overzealous + std::move + +2025-03-21 Owen Avery <powerboat9.gamer@gmail.com> + + * ast/rust-ast-collector.cc + (TokenCollector::visit): Remove visitor for NamedFunctionParam. + * ast/rust-ast-collector.h + (TokenCollector::visit): Likewise. + * ast/rust-ast-full-decls.h + (class NamedFunctionParam): Remove forward declaration. + * ast/rust-ast-visitor.cc + (DefaultASTVisitor::visit): Remove visitor for + NamedFunctionParam. + * ast/rust-ast-visitor.h + (DefaultASTVisitor::visit): Likewise. + * ast/rust-ast.cc + (NamedFunctionParam::as_string): Remove. + * ast/rust-item.h + (class NamedFunctionParam): Remove. + (class ExternalFunctionItem): Remove. + * parse/rust-parse-impl.h + (Parser::parse_named_function_param): Remove. + (Parser::parse_named_function_params): Remove. + * parse/rust-parse.h + (Parser::parse_named_function_param): Remove. + (Parser::parse_named_function_params): Remove. + +2025-03-21 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-early-name-resolver-2.0.cc + (Early::visit): Resolve the pending eager invocations inside + builtin macro invocations. + +2025-03-21 Philip Herron <herron.philip@googlemail.com> + + * hir/rust-ast-lower-stmt.cc (ASTLoweringStmt::visit): hir lowering + * hir/rust-ast-lower-stmt.h: likewise + * resolve/rust-ast-resolve-stmt.cc (ResolveStmt::visit): name resolution + * resolve/rust-ast-resolve-stmt.h: likewise + +2025-03-21 Owen Avery <powerboat9.gamer@gmail.com> + + * Make-lang.in: Handle rust-forever-stack.cc. + * resolve/rust-forever-stack.h + (class ForeverStackStore): Add. + * resolve/rust-forever-stack.cc: New file, based on + rust-forever-stack.hxx. + +2025-03-21 Om Swaroop Nayak <96killerat96@gmail.com> + + * ast/rust-collect-lang-items.cc (get_lang_item_attr): "removed checker fn" + * util/rust-attributes.cc (Attributes::is_lang_item): "added fn" + * util/rust-attributes.h: "added fn" + +2025-03-21 Philip Herron <herron.philip@googlemail.com> + + * checks/errors/rust-readonly-check.cc (check_decl): improve mut check + (emit_error): helper + (check_modify_expr): likewise + (readonly_walk_fn): reuse helper + (ReadonlyCheck::Lint): cleanup context each run + +2025-03-21 Owen Avery <powerboat9.gamer@gmail.com> + + * ast/rust-ast-visitor.cc + (DefaultASTVisitor::visit): When visiting a TraitImpl, visit its + trait path. + +2025-03-21 liushuyu <liushuyu011@gmail.com> + + * backend/rust-compile-intrinsic.cc: add the new `catch_unwind` variant + of the `try` intrinsic: this variant can be seen on Rust 1.78+ + and returns `()` instead of `i32`. + +2025-03-21 liushuyu <liushuyu011@gmail.com> + + * backend/rust-compile-intrinsic.cc: add `try` intrinsic handler. + * lang.opt: add `-frust-panic` option. + * rust-lang.cc: enable exception handler code generation. + * rust-session-manager.cc: add getter and setter for panic + strategy option. + * rust-session-manager.h: Likewise. + +2025-03-21 Philip Herron <herron.philip@googlemail.com> + + * backend/rust-compile-expr.cc (CompileExpr::visit): implement coercion + * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit): this is an LUB + * typecheck/rust-unify.cc (UnifyRules::go): remove unify ! coercion + +2025-03-21 Nobel <nobel2073@gmail.com> + + * typecheck/rust-casts.cc (TypeCastRules::cast_rules): Add rule. + +2025-03-21 Philip Herron <herron.philip@googlemail.com> + + * backend/rust-compile-expr.cc (CompileExpr::visit): new layout + * backend/rust-compile-pattern.cc (CompilePatternCheckExpr::visit): likewise + (CompilePatternBindings::visit): likewise + * backend/rust-compile-resolve-path.cc: likewise + * backend/rust-compile-type.cc (TyTyResolveCompile::visit): implement new layout + * rust-gcc.cc (constructor_expression): get rid of useless assert + +2025-03-21 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-toplevel-name-resolver-2.0.cc + (TopLevel::visit): Insert a definition for Self when visiting + InherentImpl and TraitImpl instances. + * resolve/rust-toplevel-name-resolver-2.0.h + (TopLevel::visit): Add visitors for InherentImpl and TraitImpl. + +2025-03-21 Philip Herron <herron.philip@googlemail.com> + + * hir/rust-hir-dump.cc (Dump::visit): add null guard + +2025-03-21 Philip Herron <herron.philip@googlemail.com> + + * backend/rust-compile-expr.cc (CompileExpr::visit): handle partial_eq possible call + * backend/rust-compile-expr.h: handle case where lang item calls differ from name + * hir/tree/rust-hir-expr.cc (OperatorExprMeta::OperatorExprMeta): new helper + * hir/tree/rust-hir-expr.h: likewise + * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit): handle partial_eq + (TypeCheckExpr::resolve_operator_overload): likewise + * typecheck/rust-hir-type-check-expr.h: likewise + * util/rust-lang-item.cc (LangItem::ComparisonToLangItem): map comparison to lang item + (LangItem::ComparisonToSegment): likewise + * util/rust-lang-item.h: new lang items PartialOrd and Eq + * util/rust-operators.h (enum class): likewise + +2025-03-21 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit): check for error + * typecheck/rust-tyty-call.cc (TypeCheckCallExpr::visit): likewise and remove debug error + +2025-03-21 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-default-resolver.cc + (DefaultResolver::visit): Make sure to scope visitation of the + children of type definition items. + * resolve/rust-default-resolver.h + (DefaultResolver::visit): Add overrides for TupleStruct, Union, + and TypeAlias. + * resolve/rust-late-name-resolver-2.0.cc + (Late::visit): Remove override for Enum. + * resolve/rust-late-name-resolver-2.0.h + (Late::visit): Likewise. + * resolve/rust-toplevel-name-resolver-2.0.cc + (TopLevel::visit): Rely more on DefaultResolver::visit. + * resolve/rust-toplevel-name-resolver-2.0.h + (TopLevel::visit): Remove override for BlockExpr. + +2025-03-21 Philip Herron <herron.philip@googlemail.com> + + * hir/rust-hir-dump.cc (Dump::do_qualifiedpathtype): add guard + (Dump::do_traitfunctiondecl): likewise + (Dump::visit): likewise + +2025-03-21 Prajwal S N <prajwalnadig21@gmail.com> + + * typecheck/rust-hir-type-check.h (class TypeCheckContext): add + header file and use StackedContexts for blocks + * typecheck/rust-typecheck-context.cc: update methods + * typecheck/rust-hir-trait-resolve.cc: refactor function calls + * typecheck/rust-hir-type-check-implitem.cc: refactor function calls + * typecheck/rust-hir-type-check-type.cc: refactor function calls + +2025-03-21 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-ast.h: Add new Kind enums, remove Node class. + * ast/rust-builtin-ast-nodes.h: Use new Kind enums. + * ast/rust-expr.h (class LoopLabel): Likewise. + * ast/rust-item.h: Likewise. + * ast/rust-macro.h: Likewise. + * ast/rust-path.h: Likewise. + * expand/rust-macro-builtins-helpers.cc: Likewise. + * expand/rust-macro-builtins-utility.cc (MacroBuiltin::concat_handler): Likewise. + (MacroBuiltin::stringify_handler): Likewise. + * resolve/rust-ast-resolve-expr.cc (ResolveExpr::visit): Likewise. + * resolve/rust-early-name-resolver.cc: Likewise. + * hir/rust-ast-lower.cc (ASTLoweringBlock::visit): Likewise. + +2025-03-21 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-toplevel-name-resolver-2.0.cc + (TopLevel::visit): Add visitor for TraitItemType. + * resolve/rust-toplevel-name-resolver-2.0.h + (TopLevel::visit): Likewise. + +2025-03-21 Arthur Cohen <arthur.cohen@embecosm.com> + + * resolve/rust-ast-resolve-type.cc (ResolveType::visit): New visitor to handle + ParenthesizedType. + * resolve/rust-ast-resolve-type.h: Likewise. + * typecheck/rust-hir-type-check-type.cc (TypeCheckType::visit): Likewise. + * typecheck/rust-hir-type-check-type.h: Likewise. + +2025-03-21 Arthur Cohen <arthur.cohen@embecosm.com> + + * hir/rust-ast-lower-type.cc (ASTLoweringType::visit): Add implementation for + ParenthesizedType. + * hir/rust-ast-lower-type.h: Declare that new visitor. + +2025-03-21 Owen Avery <powerboat9.gamer@gmail.com> + + * ast/rust-ast-builder-type.cc: Remove inclusion of + rust-make-unique.h. + * ast/rust-ast-builder.cc: Likewise. + (Builder::array): Use std::make_unique instead of + Rust::make_unique. + * ast/rust-ast.cc (Attribute::get_traits_to_derive): Likewise. + * ast/rust-macro.h: Remove inclusion of rust-make-unique.h. + (MacroRulesDefinition::mbe): Use std::make_unique instead of + Rust::make_unique. + (MacroRulesDefinition::decl_macro): Likewise. + * ast/rust-path.h + (PathInExpression::PathInExpression): Likewise. + (QualifiedPathInExpression::QualifiedPathInExpression): + Likewise. + * backend/rust-compile-pattern.cc + (CompilePatternCheckExpr::visit): Likewise. + * expand/rust-derive-copy.cc + (DeriveCopy::copy_impl): Likewise. + * expand/rust-expand-format-args.cc + (expand_format_args): Likewise. + * expand/rust-macro-builtins-asm.cc: Remove inclusion of + rust-make-unique.h. + (parse_asm): Use std::make_unique instead of Rust::make_unique. + * hir/rust-ast-lower-expr.cc + (ASTLoweringExpr::visit): Likewise. + * hir/tree/rust-hir-expr.cc + (StructExprStructFields::StructExprStructFields): Likewise. + (StructExprStructFields::operator=): Likewise. + * hir/tree/rust-hir.cc + (TypePath::to_trait_bound): Likewise. + * lex/rust-token.h: Remove inclusion of rust-make-unique.h. + (Token::Token): Use std::make_unique instead of + Rust::make_unique. + * metadata/rust-import-archive.cc: Remove inclusion of + rust-make-unique.h. + (Import::find_archive_export_data): Use std::make_unique instead + of Rust::make_unique. + * metadata/rust-imports.cc: Remove inclusion of + rust-make-unique.h. + (Import::find_export_data): Use std::make_unique instead of + Rust::make_unique. + (Import::find_object_export_data): Likewise. + * parse/rust-parse-impl.h: Remove inclusion of + rust-make-unique.h. + (Parser::parse_function_param): Use std::make_unique instead of + Rust::make_unique. + (Parser::parse_self_param): Likewise. + (Parser::parse_array_expr): Likewise. + * typecheck/rust-hir-type-check-enumitem.cc + (TypeCheckEnumItem::visit): Likewise. + * typecheck/rust-hir-type-check-implitem.cc + (TypeCheckTopLevelExternItem::visit): Likewise. + (TypeCheckImplItem::visit): Likewise. + * typecheck/rust-hir-type-check-type.cc + (TypeResolveGenericParam::visit): Likewise. + * typecheck/rust-hir-type-check.cc: Remove inclusion of + rust-make-unique.h. + (TraitItemReference::get_type_from_fn): Use std::make_unique + instead of Rust::make_unique. + * typecheck/rust-tyty-bounds.cc + (TypeCheckBase::get_predicate_from_bound): Likewise. + * util/rust-make-unique.h: Removed. + +2025-03-21 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-item.h: Add EnumItem::Kind for differentiating all variants that may be + used inside an enum declaration. + +2025-03-21 Owen Avery <powerboat9.gamer@gmail.com> + + * ast/rust-ast-visitor.cc + (DefaultASTVisitor::visit): Visit implicit Self parameters of + traits. + * resolve/rust-late-name-resolver-2.0.cc + (Late::visit): Resolve implicit Self parameters of traits. + * resolve/rust-late-name-resolver-2.0.h: + (Late::visit): Add trait visitor. + * resolve/rust-toplevel-name-resolver-2.0.cc + (TopLevel::visit): Insert resolutions for Self type parameters + as well. + +2025-03-21 Liam Naddell <liamnprg@gmail.com> + + * resolve/rust-late-name-resolver-2.0.cc: + Change the late name resolver to enter proper lexical scope during typechecking + * resolve/rust-late-name-resolver-2.0.h: + Add needed prototype to header + * resolve/rust-toplevel-name-resolver-2.0.cc: + Add generic parameters to enum's scoped RIB to allow for proper name resolution on types. + +2025-03-21 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-ast-builder.cc: Add new functions. + * ast/rust-ast-builder.h: Declare them. + +2025-03-21 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-path.h: Add two new constructors. + +2025-03-21 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-collect-lang-items.cc (CollectLangItems::visit): Add visitor for collecting + functions that might be lang items. + * ast/rust-collect-lang-items.h: Likewise. + +2025-03-21 Arthur Cohen <arthur.cohen@embecosm.com> + + * util/rust-lang-item.h: Add new lang items. + * util/rust-lang-item.cc: Likewise. + +2025-03-21 Arthur Cohen <arthur.cohen@embecosm.com> + + * util/rust-lang-item.h: Add Sync marker trait. + * util/rust-lang-item.cc: Likewise. + +2025-03-21 Arthur Cohen <arthur.cohen@embecosm.com> + + * typecheck/rust-hir-type-check-type.cc: Add TODO note. + +2025-03-21 Arthur Cohen <arthur.cohen@embecosm.com> + + * resolve/rust-ast-resolve-type.cc (ResolveTypeToCanonicalPath::visit): Resolve additional + trait bounds. + * resolve/rust-late-name-resolver-2.0.cc (Late::visit): Error out properly on unresolved + type-path instead of crashing. + +2025-03-21 Arthur Cohen <arthur.cohen@embecosm.com> + + * typecheck/rust-hir-path-probe.cc: Fix typos. + * typecheck/rust-hir-path-probe.h: Likewise. + * typecheck/rust-hir-type-check-path.cc: Likewise. + +2025-03-21 Nobel <nobel2073@gmail.com> + + * typecheck/rust-casts.cc (TypeCastRules::cast_rules): Add rule. + +2025-03-21 Sri Ganesh Thota <sriganeshthota12345@gmail.com> + + * ast/rust-item.h: I have changed helper constructor for typepath + to be a delegating constructor. + +2025-03-21 Philip Herron <herron.philip@googlemail.com> + + * backend/rust-compile-fnparam.cc (CompileFnParam::visit): compile tuple patterns + (CompileSelfParam::compile): update return type + (CompileFnParam::create_tmp_param_var): return Bvariable not tree to stop ICE + * backend/rust-compile-fnparam.h: update prototype + * backend/rust-compile-pattern.cc (CompilePatternBindings::visit): implement TuplePattern + * backend/rust-compile-pattern.h: update prototype + +2025-03-21 Philip Herron <herron.philip@googlemail.com> + + * rust-gcc.cc (operator_to_tree_code): ! expressions are BIT_NOT_EXPR + +2025-03-21 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-path.h: Adapt children of Path to fix some NodeId issues. + +2025-03-21 Arthur Cohen <arthur.cohen@embecosm.com> + + * resolve/rust-late-name-resolver-2.0.cc (Late::visit): New. + * resolve/rust-late-name-resolver-2.0.h: New. + +2025-03-21 Arthur Cohen <arthur.cohen@embecosm.com> + + * hir/rust-ast-lower-type.cc (ASTLowerTypePath::translate): Adapt to + handle lang item paths. + (ASTLowerTypePath::visit): Likewise. + (ASTLowerTypePath::translate_type_path): New. + (ASTLowerTypePath::translate_lang_item_type_path): New. + * hir/rust-ast-lower-type.h: Adapt to handle lang item paths. + * resolve/rust-ast-resolve-type.h: Likewise. + +2025-03-21 Arthur Cohen <arthur.cohen@embecosm.com> + + * resolve/rust-ast-resolve-item.cc (ResolveItem::visit): Adapt resolver + to lang item paths. + * resolve/rust-ast-resolve-type.h: Likewise. + +2025-03-21 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-item.h: Add new method to specifically get a type-path. + * ast/rust-path.cc (LangItemPath::as_string): Implement properly. + * hir/rust-ast-lower-type.cc (ASTLowerTypePath::translate): Adapt + visitor to use the new LangItemPath. + * hir/rust-ast-lower-type.h: Likewise. + * resolve/rust-ast-resolve-item.cc (ResolveItem::visit): Likewise. + * resolve/rust-ast-resolve-type.h: Likewise. + +2025-03-21 Arthur Cohen <arthur.cohen@embecosm.com> + + * expand/rust-derive-copy.cc: Use new LangItemPath for derive(Copy). + +2025-03-21 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-path.h (class LangItemPath): New. + (class TypePath): Adapt to accomodate LangItemPath. + * ast/rust-ast.cc (TraitImpl::as_string): Use new checks for lang items. + (QualifiedPathType::as_string): Likewise. + (FormatArgs::set_outer_attrs): Likewise. + * ast/rust-item.h (class TraitImpl): Likewise. + +2025-03-21 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-forever-stack.h + (ForeverStack::find_starting_point): Use type + 'std::reference_wrapper<Node> &' instead of 'Node &' for + parameter starting_point. + * resolve/rust-forever-stack.hxx + (ForeverStack::find_starting_point): Likewise. + (ForeverStack::resolve_path): Handle change to + ForeverStack::find_starting_point. + +2025-03-21 Arthur Cohen <arthur.cohen@embecosm.com> + + * typecheck/rust-hir-type-check-type.cc (TypeCheckType::resolve_root_path): + Remove unused capture in lambda. + +2025-03-21 Arthur Cohen <arthur.cohen@embecosm.com> + + * util/rust-attributes.h (class Attributes): New. + * util/rust-attributes.cc: Implement Attributes::is_known(). + * ast/rust-collect-lang-items.cc (is_known_attribute): Remove. + (get_lang_item_attr): Call Attributes::is_known() instead. + * hir/rust-ast-lower-base.cc (ASTLoweringBase::handle_outer_attributes): Likewise. + (ASTLoweringBase::is_known_attribute): Remove. + +2025-03-21 Arthur Cohen <arthur.cohen@embecosm.com> + + * Make-lang.in: Add new object file. + * rust-session-manager.cc (Session::compile_crate): Call CollectLangItems. + * ast/rust-collect-lang-items.cc: New file. + * ast/rust-collect-lang-items.h: New file. + +2025-03-21 Arthur Cohen <arthur.cohen@embecosm.com> + + * util/rust-hir-map.h: Keep a NodeId mappings for lang items. + * util/rust-hir-map.cc (Mappings::insert_lang_item_node): New function. + (Mappings::lookup_lang_item_node): Likewise. + +2025-03-21 Philip Herron <herron.philip@googlemail.com> + + * hir/rust-hir-dump.cc (Dump::visit): add missing check for no return value + +2025-03-21 Philip Herron <herron.philip@googlemail.com> + + * backend/rust-constexpr.cc (eval_store_expression): check for null + (eval_call_expression): remove bad warning + * rust-gcc.cc (arithmetic_or_logical_expression): add warnings + +2025-03-21 Philip Herron <herron.philip@googlemail.com> + + * backend/rust-compile-base.cc: apply coercion site to result + * backend/rust-compile-base.h: update prototype + * backend/rust-compile-implitem.cc (CompileTraitItem::visit): send in coercion info + * backend/rust-compile-item.cc (CompileItem::visit): likewise + +2025-03-21 Philip Herron <herron.philip@googlemail.com> + + * resolve/rust-ast-resolve-item.cc (ResolveItem::visit): remove assertions + +2025-03-21 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-ast-visitor.h: Replace context with StackedContexts. + * ast/rust-ast-visitor.cc (ContextualASTVisitor::visit): Use new APIs. + * checks/errors/rust-ast-validation.cc (ASTValidation::visit): Likewise. + +2025-03-21 Arthur Cohen <arthur.cohen@embecosm.com> + + * util/rust-stacked-contexts.h: Add new method to see what context we are currently in. + +2025-03-21 Arthur Cohen <arthur.cohen@embecosm.com> + + * hir/tree/rust-hir-item.h: Remove TraitItemFunc::has_block_defined() + * backend/rust-compile-implitem.cc (CompileTraitItem::visit): + Call TraitItemFunc::has_definition() instead. + * checks/errors/rust-const-checker.cc (ConstChecker::visit): Likewise. + * checks/errors/rust-hir-pattern-analysis.cc (PatternChecker::visit): Likewise. + * checks/errors/rust-unsafe-checker.cc (UnsafeChecker::visit): Likewise. + * typecheck/rust-hir-trait-resolve.cc (ResolveTraitItemToRef::visit): Likewise. + +2025-03-21 Arthur Cohen <arthur.cohen@embecosm.com> + + * util/rust-hir-map.h: Move definitions from header... + * util/rust-hir-map.cc: ...to source file. + +2025-03-21 Arthur Cohen <arthur.cohen@embecosm.com> + + * util/rust-lang-item.h: Fix comment location to align with other comments. + +2025-03-21 Philip Herron <herron.philip@googlemail.com> + + * backend/rust-compile-type.cc (TyTyResolveCompile::visit): call lauout type directly + * rust-backend.h (struct_type): add optional layout parameter + (union_type): likewise + (fill_in_fields): likewise + * rust-gcc.cc (struct_type): likewise + (union_type): likewise + (fill_in_fields): only layout if we required + +2025-03-21 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-casts.cc (TypeCastRules::cast_rules): allow casts to float + +2025-03-21 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-hir-trait-resolve.cc (TraitResolver::resolve_trait): track trait + * typecheck/rust-hir-type-check-implitem.cc: trait block + * typecheck/rust-hir-type-check-path.cc (TypeCheckExpr::resolve_segments): dont when dyn + * typecheck/rust-hir-type-check-type.cc (TypeCheckType::visit): look at Self contenxt + (TypeCheckType::resolve_root_path): track if Self + (TypeCheckType::resolve_associated_type): look at current context for associated types + * typecheck/rust-hir-type-check-type.h: change prototype + * typecheck/rust-hir-type-check.h (class TypeCheckBlockContextItem): + new context system to track current state + * typecheck/rust-typecheck-context.cc (TypeCheckContext::have_block_context): likewise + (TypeCheckContext::peek_block_context): likewise + (TypeCheckContext::push_block_context): likewise + (TypeCheckContext::pop_block_context): likewise + (TypeCheckBlockContextItem::Item::Item): likewise + (TypeCheckBlockContextItem::TypeCheckBlockContextItem): likewise + (TypeCheckBlockContextItem::is_impl_block): likewise + (TypeCheckBlockContextItem::is_trait_block): likewise + (TypeCheckBlockContextItem::get_impl_block): likewise + (TypeCheckBlockContextItem::get_trait): likewise + +2025-03-21 Philip Herron <herron.philip@googlemail.com> + + * hir/rust-hir-dump.cc (Dump::visit): add missing null checks + +2025-03-21 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * backend/rust-compile-base.cc: Prepend crate name to function's ir + name. + +2025-03-21 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-name-resolver.cc: Include options.txt. + (Resolver::insert_resolved_name): Assert that name resolution + 2.0 is disabled. + (Resolver::lookup_resolved_name): Likewise. + (Resolver::insert_resolved_type): Likewise. + (Resolver::lookup_resolved_type): Likewise. + (Resolver::insert_resolved_label): Likewise. + (Resolver::lookup_resolved_label): Likewise. + (Resolver::insert_resolved_macro): Likewise. + (Resolver::lookup_resolved_macro): Likewise. + (Resolver::insert_resolved_misc): Likewise. + (Resolver::lookup_resolved_misc): Likewise. + +2025-03-21 Philip Herron <herron.philip@googlemail.com> + + * backend/rust-compile-expr.cc (check_match_scrutinee): check for empty match + (CompileExpr::visit): fix assertion + * checks/errors/rust-hir-pattern-analysis.cc (check_match_usefulness): check for empty + * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit): resolve to ! + +2025-03-21 Philip Herron <herron.philip@googlemail.com> + + * hir/rust-hir-dump.cc (Dump::visit): add guards + +2025-03-21 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * ast/rust-stmt.h: Remove stdlib include and use rust-system instead. + * backend/rust-compile-expr.cc: Likewise. + * backend/rust-mangle-legacy.cc: Likewise. + * backend/rust-mangle-v0.cc: Likewise. + * hir/rust-hir-dump.cc: Likewise. + * typecheck/rust-hir-type-check-type.cc: Likewise. + * typecheck/rust-tyty.cc: Likewise. + * typecheck/rust-tyty.h: Likewise. + * util/rust-common.h: Likewise. + * util/rust-token-converter.cc: Likewise. + * util/rust-token-converter.h: Likewise. + +2025-03-21 Owen Avery <powerboat9.gamer@gmail.com> + + * typecheck/rust-hir-type-check-expr.cc: Add includes. + (TypeCheckExpr::visit): Use name resolver 2.0. + (TypeCheckExpr::resolve_operator_overload): Likewise. + (TypeCheckExpr::resolve_fn_trait_call): Likewise. + * typecheck/rust-hir-type-check-path.cc + (TypeCheckExpr::visit): Likewise. + (TypeCheckExpr::resolve_segments): Likewise. + * typecheck/rust-hir-type-check-type.cc + (TypeCheckType::resolve_segments): Likewise. + (ResolveWhereClauseItem::visit): Likewise. + (TypeCheckType::visit): Avoid usage of + Resolver::get_unit_type_node_id when handling TupleType, use + name resolver 2.0 when handling QualifiedPathInType. + +2025-03-21 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-late-name-resolver-2.0.cc + (Late::visit): Call DefaultResolver::visit when visiting + TypePath. + +2025-03-21 Owen Avery <powerboat9.gamer@gmail.com> + + * checks/errors/privacy/rust-privacy-reporter.cc + (PrivacyReporter::check_for_privacy_violation): Use name + resolver 2.0. + +2025-03-21 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * backend/rust-compile-expr.cc (CompileExpr::visit): Change call. + (CompileExpr::resolve_operator_overload): Update function arguments. + * backend/rust-compile-expr.h: Change the function's prototype to use + a reference wrapper instead of a reference within the optional. + +2025-03-21 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * typecheck/rust-tyty.h: Change initializer list to default constructor + call. + +2025-03-21 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * hir/rust-ast-lower-expr.cc (ASTLoweringExpr::visit): Add template + to tl::optional. + * hir/rust-ast-lower-type.cc (ASTLowerGenericParam::visit): Likewise. + * typecheck/rust-hir-type-check-type.cc (TypeResolveGenericParam::visit): + Likewise. + +2025-03-21 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * typecheck/rust-tyty-call.cc (TypeCheckCallExpr::visit): Do not + get a reference if the pattern does not exist. + (TypeCheckMethodCallExpr::check): Likewise. + +2025-03-21 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * hir/rust-ast-lower-stmt.cc (ASTLoweringStmt::visit): Change the + ternary expression with a more readable if. + +2025-03-21 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * typecheck/rust-tyty.h: Reverse monomorphization during cloning and + make a new function to explicitly monomorphize. + * typecheck/rust-tyty.cc: Use monomorphization when required. + +2025-03-21 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * hir/rust-ast-lower-type.cc (ASTLowerGenericParam::visit): Forward + an optional to the constructor. + * hir/tree/rust-hir-item.cc (TypeParam::TypeParam): Use an optional + in the constructor. + (TypeParam::operator=): Ensure the TypeParam has a type properly. + (TypeParam::get_type_mappings): Likewise. + * hir/tree/rust-hir-item.h: Wrap the type smart pointer into an + optional. + * hir/tree/rust-hir.cc (TypeParam::as_string): Unwrap optional type + correctly. + +2025-03-21 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * backend/rust-compile-expr.cc (CompileExpr::visit): Call getter + instead of size function. + * checks/errors/privacy/rust-privacy-reporter.cc (PrivacyReporter::visit): + Only check privacy if the type is present. + * hir/rust-ast-lower-stmt.cc (ASTLoweringStmt::visit): Use an optional. + * hir/tree/rust-hir-generic-param.h: Assert type before getting it. + * hir/tree/rust-hir-item.h: Assert pointers before dereference, fix + has_type condition. + * hir/tree/rust-hir-path.h: Add more assertions. + * hir/tree/rust-hir-stmt.cc: Change constructor with optionals. + * hir/tree/rust-hir-stmt.h: Use optionals over smart pointers to + emphasize these fields might be missing. + * hir/tree/rust-hir.cc (LetStmt::as_string): Use getters. + * typecheck/rust-hir-type-check-expr.cc: Clone structures to prevent + parent's fields from being nulled by the move operation. + * typecheck/rust-hir-type-check-item.cc (TypeCheckItem::visit): Use + optionals. + * typecheck/rust-tyty.cc: Likewise. + * typecheck/rust-tyty.h: Likewise. + +2025-03-21 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * Make-lang.in: Add new files. + * hir/tree/rust-hir-item.h: Move Item definition and remove + implementations to their corresponding cc file. + * hir/tree/rust-hir-expr.h: Move implementation to the corresponding + cc file. + * hir/tree/rust-hir-path.h: Likewise. + * hir/tree/rust-hir-pattern.h: Likewise. + * hir/tree/rust-hir-stmt.h: Likewise. + * hir/tree/rust-hir-type.h: Likewise. + * hir/tree/rust-hir-visitor.h: Likewise. + * hir/tree/rust-hir.h: Likewise. + * hir/tree/rust-hir.cc (Crate::Crate): Add implementations from Crate + and remove ConstGenericParam implementations to move them to their + own file. + * hir/tree/rust-hir-attrs.h: New file. + * hir/tree/rust-hir-bound-abstract.h: New file. + * hir/tree/rust-hir-bound.h: New file. + * hir/tree/rust-hir-expr-abstract.h: New file. + * hir/tree/rust-hir-expr.cc: New file. + * hir/tree/rust-hir-generic-param.cc: New file. + * hir/tree/rust-hir-generic-param.h: New file. + * hir/tree/rust-hir-item.cc: New file. + * hir/tree/rust-hir-literal.h: New file. + * hir/tree/rust-hir-node.h: New file. + * hir/tree/rust-hir-path.cc: New file. + * hir/tree/rust-hir-pattern-abstract.h: New file. + * hir/tree/rust-hir-simple-path.h: New file. + * hir/tree/rust-hir-stmt.cc: New file. + * hir/tree/rust-hir-trait-bound.h: New file. + * hir/tree/rust-hir-type-abstract.cc: New file. + * hir/tree/rust-hir-type-abstract.h: New file. + * hir/tree/rust-hir-type-no-bounds.h: New file. + * hir/tree/rust-hir-type.cc: New file. + * hir/tree/rust-hir-visibility.h: New file. + * hir/tree/rust-hir-visitable.h: New file. + * checks/lints/rust-lint-marklive.h: Use References. + * hir/rust-ast-lower-expr.cc (ASTLoweringExpr::visit): Reformat + vectors. + * hir/rust-hir-dump.cc (Dump::visit): Use reference. + * typecheck/rust-hir-type-check-struct.cc (TypeCheckStructExpr::resolve): + Use references. + * typecheck/rust-tyty-bounds.cc: Likewise. + +2025-03-21 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * backend/rust-compile-base.cc: Use FnParam getter. + * backend/rust-compile-expr.cc (CompileExpr::visit): Likewise. + * backend/rust-compile-intrinsic.cc: Likewise. + * backend/rust-compile-type.cc: Likewise. + * checks/errors/privacy/rust-privacy-reporter.cc (PrivacyReporter::visit): + Only visit childrens if not missing. + * checks/errors/rust-unsafe-checker.cc (UnsafeChecker::visit): Use + a reference instead of a raw pointer. + * hir/tree/rust-hir-expr.h: Add presence function for return + expression. + * hir/tree/rust-hir-item.h: Remove take_param_name. + * hir/tree/rust-hir.h: Make mapping getter const. + * typecheck/rust-hir-dot-operator.cc (MethodResolver::Select): Use + getter. + * typecheck/rust-hir-type-check-expr.cc: Likewise. + * typecheck/rust-hir-type-check-implitem.cc: Use FnParam vector instead + of std::pair of Pattern and BaseType. + * typecheck/rust-hir-type-check-item.cc: Likewise. + * typecheck/rust-hir-type-check.cc: Likewise. + * typecheck/rust-tyty-call.cc (TypeCheckCallExpr::visit): Use getters. + (TypeCheckMethodCallExpr::check): Likewise. + * typecheck/rust-tyty-cmp.h: Likewise. + * typecheck/rust-tyty.cc: Use FnParam. + * typecheck/rust-tyty.h (class FnParam): Add FnParam to handle function + parameters instead of handling std::pairs. + * typecheck/rust-unify.cc (UnifyRules::expect_fndef): Use getters. + (UnifyRules::expect_fnptr): Likewise. + +2025-03-21 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * backend/rust-compile-base.cc (HIRCompileBase::compile_function_body): + Remove usage of get function to retrieve a raw pointer. + * backend/rust-compile-base.h: + Change API usage from raw pointer to a reference. + * backend/rust-compile-block.cc (CompileBlock::compile): Likewise. + (CompileBlock::visit): Likewise. + (CompileConditionalBlocks::visit): Likewise. + * backend/rust-compile-block.h: Likewise. + * backend/rust-compile-expr.cc (CompileExpr::Compile): Likewise. + (CompileExpr::visit): Likewise. + (check_match_scrutinee): Likewise. + (CompileExpr::array_value_expr): Likewise. + (CompileExpr::array_copied_expr): Likewise. + (CompileExpr::generate_closure_function): Likewise. + (CompileExpr::generate_possible_fn_trait_call): Likewise. + * backend/rust-compile-expr.h: Likewise. + * backend/rust-compile-fnparam.cc (CompileFnParam::compile): Likewise. + (CompileFnParam::visit): Likewise. + * backend/rust-compile-fnparam.h: Likewise. + * backend/rust-compile-implitem.cc (CompileTraitItem::visit): Likewise. + * backend/rust-compile-intrinsic.cc (compile_fn_params): Likewise. + * backend/rust-compile-item.cc (CompileItem::visit): Likewise. + * backend/rust-compile-pattern.cc (CompilePatternCheckExpr::visit): + Likewise. + (compile_range_pattern_bound): Likewise. + (CompilePatternBindings::visit): Likewise. + (CompilePatternLet::visit): Likewise. + * backend/rust-compile-pattern.h: Likewise. + * backend/rust-compile-resolve-path.cc (ResolvePathRef::resolve): + Likewise. + (HIRCompileBase::query_compile): Likewise. + * backend/rust-compile-stmt.cc (CompileStmt::visit): Likewise. + * backend/rust-compile-struct-field-expr.cc (CompileStructExprField::Compile): + Likewise. + (CompileStructExprField::visit): Likewise. + * backend/rust-compile-struct-field-expr.h: Likewise. + * backend/rust-compile-type.cc (TyTyResolveCompile::visit): Likewise. + * backend/rust-compile-var-decl.h: Likewise. + * backend/rust-compile.cc: Likewise. + * backend/rust-mangle-v0.cc (v0_inherent_or_trait_impl_path): Likewise. + * checks/errors/borrowck/rust-bir-builder-expr-stmt.cc (ExprStmtBuilder::visit): + Likewise. + * checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h: Likewise. + * checks/errors/borrowck/rust-bir-builder-pattern.h: Likewise. + * checks/errors/borrowck/rust-bir-builder-struct.h: Likewise. + * checks/errors/borrowck/rust-bir-builder.h: Likewise. + * checks/errors/borrowck/rust-function-collector.h: Likewise. + * checks/errors/privacy/rust-privacy-reporter.cc (PrivacyReporter::check_type_privacy): + Likewise. + (PrivacyReporter::visit): Likewise. + * checks/errors/privacy/rust-privacy-reporter.h: Likewise. + * checks/errors/privacy/rust-reachability.cc (ReachabilityVisitor::visit): + Likewise. + * checks/errors/rust-const-checker.cc (ConstChecker::visit): Likewise. + * checks/errors/rust-unsafe-checker.cc (UnsafeChecker::visit): + Likewise. + * checks/lints/rust-lint-marklive.cc (MarkLive::visit): Likewise. + * checks/lints/rust-lint-marklive.h: Likewise. + * hir/rust-hir-dump.cc (Dump::visit): Likewise. + * hir/tree/rust-hir-expr.h: Likewise. + * hir/tree/rust-hir-item.h: Likewise. + * hir/tree/rust-hir-path.h: Likewise. + * hir/tree/rust-hir-pattern.h: Likewise. + * hir/tree/rust-hir-stmt.h: Likewise. + * hir/tree/rust-hir-type.h: Likewise. + * hir/tree/rust-hir.h: Likewise. + * typecheck/rust-autoderef.cc: Likewise. + * typecheck/rust-hir-dot-operator.cc (MethodResolver::select): + Likewise. + * typecheck/rust-hir-inherent-impl-overlap.h: Likewise. + * typecheck/rust-hir-path-probe.cc (PathProbeType::process_impl_item_candidate): + Likewise. + (PathProbeImplTrait::process_trait_impl_items_for_candidates): Likewise. + * typecheck/rust-hir-trait-resolve.cc (TraitResolver::resolve_trait): + Likewise. + (TraitItemReference::resolve_item): Likewise. + * typecheck/rust-hir-type-check-base.cc: Likewise. + * typecheck/rust-hir-type-check-base.h: Likewise. + * typecheck/rust-hir-type-check-enumitem.cc (TypeCheckEnumItem::Resolve): + Likewise. + (TypeCheckEnumItem::visit): Likewise. + * typecheck/rust-hir-type-check-enumitem.h: Likewise. + * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::Resolve): + Likewise. + (TypeCheckExpr::visit): Likewise. + (TypeCheckExpr::resolve_fn_trait_call): Likewise. + * typecheck/rust-hir-type-check-expr.h: Likewise. + * typecheck/rust-hir-type-check-implitem.cc (TypeCheckTopLevelExternItem::Resolve): + Likewise. + (TypeCheckTopLevelExternItem::visit): Likewise. + (TypeCheckImplItem::visit): Likewise. + (TypeCheckImplItemWithTrait::visit): Likewise. + * typecheck/rust-hir-type-check-implitem.h: Likewise. + * typecheck/rust-hir-type-check-item.cc (TypeCheckItem::visit): Likewise. + (TypeCheckItem::resolve_impl_item): Likewise. + (TypeCheckItem::resolve_impl_block_substitutions): Likewise. + (TypeCheckItem::resolve_impl_block_self): Likewise. + * typecheck/rust-hir-type-check-path.cc (TypeCheckExpr::visit): Likewise. + (TypeCheckExpr::resolve_segments): Likewise. + * typecheck/rust-hir-type-check-pattern.cc (TypeCheckPattern::Resolve): + Likewise. + (TypeCheckPattern::visit): Likewise. + (ClosureParamInfer::Resolve): Likewise. + (ClosureParamInfer::visit): Likewise. + * typecheck/rust-hir-type-check-pattern.h: Likewise. + * typecheck/rust-hir-type-check-stmt.cc (TypeCheckStmt::Resolve): + Likewise. + (TypeCheckStmt::visit): Likewise. + * typecheck/rust-hir-type-check-stmt.h: Likewise. + * typecheck/rust-hir-type-check-struct-field.h: Likewise. + * typecheck/rust-hir-type-check-struct.cc (TypeCheckStructExpr::TypeCheckStructExpr): + Likewise. + (TypeCheckStructExpr::Resolve): Likewise. + (TypeCheckStructExpr::resolve): Likewise. + (TypeCheckStructExpr::visit): Likewise. + * typecheck/rust-hir-type-check-type.cc (TypeCheckResolveGenericArguments::resolve): + Likewise. + (TypeCheckType::Resolve): Likewise. + (TypeCheckType::visit): Likewise. + (TypeCheckType::resolve_root_path): Likewise. + (TypeResolveGenericParam::Resolve): Likewise. + (TypeResolveGenericParam::visit): Likewise. + (ResolveWhereClauseItem::visit): Likewise. + * typecheck/rust-hir-type-check-type.h: Likewise. + * typecheck/rust-hir-type-check.cc (TraitItemReference::get_type_from_fn): + Likewise. + * typecheck/rust-hir-type-check.h: Likewise. + * typecheck/rust-type-util.cc (query_type): Likewise. + * typecheck/rust-typecheck-context.cc (TypeCheckContextItem::TypeCheckContextItem): + Likewise. + * typecheck/rust-tyty-bounds.cc (TypeBoundsProbe::scan): Likewise. + (TypeCheckBase::get_predicate_from_bound): Likewise. + * typecheck/rust-tyty-call.cc (TypeCheckCallExpr::visit): Likewise. + (TypeCheckMethodCallExpr::go): Likewise. + (TypeCheckMethodCallExpr::check): Likewise. + * typecheck/rust-tyty-subst.cc: Likewise. + * typecheck/rust-tyty.cc (BaseType::monomorphized_clone): Likewise. + (VariantDef::VariantDef): Remove copy constructor. + (VariantDef::operator=): Change to move operator. + (VariantDef::get_discriminant): Replace return type to a reference + instead of a reference to a unique pointer. + (VariantDef::clone): Change to references. + (VariantDef::monomorphized_clone): Likewise. + (FnType::as_string): Likewise. + (FnType::clone): Likewise. + * typecheck/rust-tyty.h: Likewise. + * util/rust-hir-map.cc (Mappings::insert_hir_impl_block): Likewise. + * backend/rust-compile-asm.cc: Use a reference instead of the raw + pointer value. + * checks/errors/borrowck/rust-bir-builder-pattern.cc: Use references. + * checks/errors/rust-hir-pattern-analysis.cc: Likewise. + +2025-03-21 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-toplevel-name-resolver-2.0.cc + (TopLevel::visit): Use DefaultResolver::visit and avoid a call + to Identifier::as_string while handling instances of StaticItem. + +2025-03-21 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-forever-stack.h + (ForeverStack::push): Accept argument of type Rib::Kind rather + than Rib. + * resolve/rust-forever-stack.hxx + (ForeverStack::push): Likewise. + * resolve/rust-name-resolution-context.cc + (NameResolutionContext::scoped): Likewise. + * resolve/rust-name-resolution-context.h + (NameResolutionContext::scoped): Likewise. + +2025-03-21 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-hir-type-check-item.cc (TypeCheckItem::resolve_impl_block_substitutions): + dont check for unconstrained when the self is not resolved + * typecheck/rust-hir-type-check-type.cc (TypeCheckType::resolve_root_path): + remove bad debug error diagnostic + * typecheck/rust-tyty-subst.cc: likewise + +2025-03-21 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-expr.h: Remove invalid usage of `struct`. + * backend/rust-compile-asm.h: Remove unused `translated` member. + * backend/rust-compile-asm.cc (CompileAsm::CompileAsm): Remove usage + of `translated` member. + * checks/errors/rust-unsafe-checker.h: Mark visitor as `override`. + * hir/tree/rust-hir-expr.h (struct AnonConst): Remove unused `locus` + member. + +2025-03-21 Arthur Cohen <arthur.cohen@embecosm.com> + + * typecheck/rust-tyty-call.h: Remove unused context member. + +2025-03-21 Arthur Cohen <arthur.cohen@embecosm.com> + + * hir/tree/rust-hir.h: Add override qualifier to overriden method. + +2025-03-21 Owen Avery <powerboat9.gamer@gmail.com> + + * ast/rust-item.h + (Trait::self_param): Add. + (Trait::Trait): Initialize self_param. + (Trait::operator=): Copy self_param. + (Trait::insert_implicit_self): Remove. + (Trait::get_implicit_self): Add. + * hir/rust-ast-lower-item.cc + (ASTLoweringItem::visit): Make sure implicit self is still + lowered to HIR. + * resolve/rust-ast-resolve-item.cc + (ResolveItem::visit): Adjust handling of implicit self. + * resolve/rust-early-name-resolver.cc + (EarlyNameResolver::visit): Add commit to Trait visitor + mentioning that implicit self is not visited. + * resolve/rust-toplevel-name-resolver-2.0.cc + (TopLevel::visit): Remove call to Trait::insert_implicit_self. + +2025-03-21 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-hir-type-check-item.cc (TypeCheckItem::visit): fix the ty_id + +2025-03-21 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-tyty.cc (PlaceholderType::can_resolve): check for empty mappings + +2025-03-21 Owen Avery <powerboat9.gamer@gmail.com> + + * checks/errors/privacy/rust-privacy-reporter.cc: + Include rust-immutable-name-resolution-context.h. + (is_child_module): Use ForeverStack::is_module_descendant if name + resolution 2.0 is enabled. + * resolve/rust-forever-stack.h + (ForeverStack::is_module_descendant): Add. + (ForeverStack::dfs_node): Add. + * resolve/rust-forever-stack.hxx + (ForeverStack::dfs_rib): Use ForeverStack::dfs_node. + (ForeverStack::dfs_node): Add. + (ForeverStack::is_module_descendant): Add. + +2025-03-21 Owen Avery <powerboat9.gamer@gmail.com> + + * checks/errors/privacy/rust-visibility-resolver.cc: + Add includes. + (VisibilityResolver::resolve_module_path): Use name resolver 2.0 + (when enabled) to lookup path resolutions. + +2025-03-21 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-hir-type-check-path.cc (TypeCheckExpr::resolve_root_path): dont infer here + +2025-03-21 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-late-name-resolver-2.0.cc + (Late::visit): Handle StructExprStruct and use + ForeverStack::resolve_path instead of ForeverStack::get to + resolve struct expression paths. + * resolve/rust-late-name-resolver-2.0.h + (Late::visit): Handle StructExprStruct. + +2025-03-21 Owen Avery <powerboat9.gamer@gmail.com> + + * backend/rust-compile-context.cc + (Context::setup_builtins): Use TypeCheckContext::get_builtins + instead of Resolver::get_builtin_types, + TypeCheckContext::lookup_type_by_node_id, and + TypeCheckContext::lookup_type. + * typecheck/rust-hir-type-check.h + (TypeCheckContext::get_builtins): Add. + * typecheck/rust-typecheck-context.cc + (TypeCheckContext::get_builtins): Add. + +2025-03-21 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-hir-type-check-path.cc (TypeCheckExpr::resolve_segments): remove hack + +2025-03-21 Owen Avery <powerboat9.gamer@gmail.com> + + * typecheck/rust-tyty.cc + (TupleType::get_unit_type): Remove parameter, cache return + value. + * typecheck/rust-tyty.h + (TupleType::get_unit_type): Remove parameter. + * resolve/rust-late-name-resolver-2.0.cc + (Late::setup_builtin_types): Adjust calls to get_unit_type. + * resolve/rust-name-resolver.cc + (Resolver::generate_builtins): Likewise. + * typecheck/rust-hir-type-check-expr.cc + (TypeCheckExpr::visit): Likewise. + * typecheck/rust-hir-type-check-implitem.cc + (TypeCheckTopLevelExternItem::visit): Likewise. + (TypeCheckImplItem::visit): Likewise. + * typecheck/rust-hir-type-check-item.cc + (TypeCheckItem::visit): Likewise. + * typecheck/rust-hir-type-check-stmt.cc + (TypeCheckStmt::visit): Likewise. + * typecheck/rust-hir-type-check-type.cc + (TypeCheckType::visit): Likewise. + * typecheck/rust-hir-type-check.cc + (TraitItemReference::get_type_from_fn): Likewise. + +2025-03-21 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-late-name-resolver-2.0.cc + (Late::visit): Handle SelfParam. + * resolve/rust-late-name-resolver-2.0.h + (Late::visit): Likewise. + +2025-03-21 Owen Avery <powerboat9.gamer@gmail.com> + + * typecheck/rust-hir-trait-resolve.cc: Add includes. + (TraitResolver::resolve_path_to_trait): + Use name resolution 2.0 resolver when enabled. + +2025-03-21 Marc Poulhiès <dkm@kataplop.net> + + * backend/rust-compile-block.h: Adjust after removal of + HIR::IfLetExpr and HIR::IfLetExprConseqElse. + * backend/rust-compile-expr.h: Likewise. + * checks/errors/borrowck/rust-bir-builder-expr-stmt.cc + (ExprStmtBuilder::visit): Likewise. + * checks/errors/borrowck/rust-bir-builder-expr-stmt.h: Likewise. + * checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h: + Likewise. + * checks/errors/borrowck/rust-bir-builder-struct.h: Likewise. + * checks/errors/borrowck/rust-function-collector.h: Likewise. + * checks/errors/privacy/rust-privacy-reporter.cc + (PrivacyReporter::visit): Likewise. + * checks/errors/privacy/rust-privacy-reporter.h: Likewise. + * checks/errors/rust-const-checker.cc (ConstChecker::visit): + Likewise. + * checks/errors/rust-const-checker.h: Likewise. + * checks/errors/rust-unsafe-checker.cc (UnsafeChecker::visit): + Likewise. + * checks/errors/rust-unsafe-checker.h: Likewise. + * hir/rust-ast-lower-block.h (ASTLoweringIfLetBlock::translate): + Change return type. + * hir/rust-ast-lower.cc (ASTLoweringIfLetBlock::desugar_iflet): + New. + (ASTLoweringIfLetBlock::visit(AST::IfLetExpr &)): Adjust and use + desugar_iflet. + * hir/rust-ast-lower.h: Add comment. + * hir/rust-hir-dump.cc (Dump::do_ifletexpr): Remove. + (Dump::visit(IfLetExpr&)): Remove. + (Dump::visit(IfLetExprConseqElse&)): Remove. + * hir/rust-hir-dump.h (Dump::do_ifletexpr): Remove. + (Dump::visit(IfLetExpr&)): Remove. + (Dump::visit(IfLetExprConseqElse&)): Remove. + * hir/tree/rust-hir-expr.h (class IfLetExpr): Remove. + (class IfLetExprConseqElse): Remove. + * hir/tree/rust-hir-full-decls.h (class IfLetExpr): Remove. + (class IfLetExprConseqElse): Remove. + * hir/tree/rust-hir-visitor.h: Adjust after removal of + HIR::IfLetExpr and HIR::IfLetExprConseqElse. + * hir/tree/rust-hir.cc (IfLetExpr::as_string): Remove. + (IfLetExprConseqElse::as_string): Remove. + (IfLetExpr::accept_vis): Remove. + (IfLetExprConseqElse::accept_vis): Remove. + * hir/tree/rust-hir.h: Adjust after removal of HIR::IfLetExpr and + HIR::IfLetExprConseqElse. + * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit): + Likewise. + * typecheck/rust-hir-type-check-expr.h: Likewise. + * checks/errors/rust-hir-pattern-analysis.cc + (PatternChecker::visit (IfLetExpr &)): Remove. + (PatternChecker::visit (IfLetExprConseqElse &)): Remove. + * checks/errors/rust-hir-pattern-analysis.h (visit(IfLetExpr &)): Remove. + (visit(IfLetExprConseqElse &)): Remove. + +2025-03-21 Owen Avery <powerboat9.gamer@gmail.com> + + * checks/errors/rust-unsafe-checker.cc: Add includes. + (UnsafeChecker::visit): Use 2.0 version of resolver when name + resolution 2.0 is enabled. + +2025-03-21 Owen Avery <powerboat9.gamer@gmail.com> + + * backend/rust-compile-implitem.cc + (CompileTraitItem::visit): Use name resolver 2.0 (when enabled) + to obtain canonical paths for instances of TraitItemConst and + TraitItemFunc. + +2025-03-21 Owen Avery <powerboat9.gamer@gmail.com> + + * typecheck/rust-hir-type-check.cc: Add includes. + (TraitItemReference::get_type_from_fn): Use + ForeverStack::to_canonical_path when name resolution 2.0 is + enabled. + +2025-03-21 Owen Avery <powerboat9.gamer@gmail.com> + + * ast/rust-path.h + (PathIdentSegment::is_super_segment): Rename to... + (PathIdentSegment::is_super_path_seg): ...here. + (PathIdentSegment::is_crate_segment): Rename to... + (PathIdentSegment::is_crate_path_seg): ...here. + (PathIdentSegment::is_lower_self): Rename to... + (PathIdentSegment::is_lower_self_seg): ...here. + (PathIdentSegment::is_big_self): Rename to... + (PathIdentSegment::is_big_self_seg): ...here. + (PathExprSegment::is_super_path_seg): Handle renames. + (PathExprSegment::is_crate_path_seg): Likewise. + (PathExprSegment::is_lower_self_seg): Likewise. + (TypePathSegment::is_crate_path_seg): Likewise. + (TypePathSegment::is_super_path_seg): Likewise. + (TypePathSegment::is_big_self_seg): Likewise. + (TypePathSegment::is_lower_self_seg): Likewise. + * ast/rust-ast-collector.cc + (TokenCollector::visit): Likewise. + +2025-03-21 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-late-name-resolver-2.0.cc + (Late::visit): Visit the initialization expressions of let + statements before visiting their patterns. + +2025-03-21 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-toplevel-name-resolver-2.0.cc + (TopLevel::visit): Insert trait names into the type namespace. + +2025-03-21 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-hir-trait-reference.h: new get locus helper + * typecheck/rust-hir-trait-resolve.cc (AssociatedImplTrait::get_locus): implemention + * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::resolve_operator_overload): + fix overload + +2025-03-19 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-toplevel-name-resolver-2.0.cc + (TopLevel::visit): Handle ExternalStaticItem. + * resolve/rust-toplevel-name-resolver-2.0.h + (TopLevel::visit): Likewise. + +2025-03-19 Owen Avery <powerboat9.gamer@gmail.com> + + * checks/errors/rust-hir-pattern-analysis.cc: Add includes. + (PatternChecker::visit): Use name resolver 2.0 when enabled. + +2025-03-19 Owen Avery <powerboat9.gamer@gmail.com> + + * backend/rust-compile-expr.cc + (CompileExpr::visit): Use name resolver 2.0 to lookup label + definitions for break and continue statements when name + resolution 2.0 is enabled. + +2025-03-19 Owen Avery <powerboat9.gamer@gmail.com> + + * checks/errors/rust-const-checker.cc: Add includes. + (ConstChecker::visit): Use name resolver 2.0 to lookup + function definitions when name resolution 2.0 is enabled. + +2025-03-19 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-toplevel-name-resolver-2.0.cc + (TopLevel::visit): Load unloaded modules before attempting to + visit their items. + +2025-03-19 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-forever-stack.h + (ForeverStack::to_canonical_path): Make const. + (ForeverStack::to_rib): Add const overload. + (ForeverStack::reverse_iter): Add const overloads. + (ForeverStack::ConstDfsResult): Add. + (ForeverStack::dfs): Add const overload. + (ForeverStack::dfs_rib): Likewise. + * resolve/rust-forever-stack.hxx + (ForeverStack::reverse_iter): Add const overloads. + (ForeverStack::dfs): Add const overload. + (ForeverStack::to_canonical_path): Make const. + (ForeverStack::dfs_rib): Likewise. + (ForeverStack::to_rib): Add const overload. + +2025-03-19 Owen Avery <powerboat9.gamer@gmail.com> + + * checks/lints/rust-lint-marklive.cc + (MarkLive::visit_path_segment): Use name resolver 2.0 when + enabled. + (MarkLive::visit): Likewise. + +2025-03-19 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-toplevel-name-resolver-2.0.cc + (TopLevel::visit): Handle ConstGenericParam. + * resolve/rust-toplevel-name-resolver-2.0.h + (TopLevel::visit): Likewise. + +2025-03-19 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-late-name-resolver-2.0.cc + (Late::visit): Visit GenericArgs and GenericArg, the former + because the latter involves a non-virtual member function call. + * resolve/rust-late-name-resolver-2.0.h + (Late::visit): Likewise. + +2025-03-19 badumbatish <tanghocle456@gmail.com> + + * expand/rust-macro-builtins-asm.cc (parse_reg_operand_in): Fix + compiler error on ast wrong implicit construct push_back + +2025-03-19 badumbatish <tanghocle456@gmail.com> + + * backend/rust-compile-asm.cc (CompileAsm::asm_construct_inputs): + Provide input operand for gccrs + * expand/rust-macro-builtins-asm.cc (parse_reg_operand_in): + Move expr to In + (expand_inline_asm_strings): + Add comments to debug strings + +2025-03-19 Owen Avery <powerboat9.gamer@gmail.com> + + * typecheck/rust-hir-type-check-pattern.cc: Add includes. + (TypeCheckPattern::visit): Use name resolver 2.0 if enabled. + * resolve/rust-name-resolution-context.cc + (NameResolutionContext::lookup): Make const qualified. + * resolve/rust-name-resolution-context.h + (NameResolutionContext::lookup): Likewise. + +2025-03-19 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-late-name-resolver-2.0.cc + (Late::visit): Allow IdentifierExpr and PathInExpression to + reference types as well as values, remove ability for + IdentifierExpr to reference labels. + +2025-03-19 Owen Avery <powerboat9.gamer@gmail.com> + + * ast/rust-ast-visitor.cc + (DefaultASTVisitor::visit): Visit fields of InlineAsm. + +2025-03-19 Owen Avery <powerboat9.gamer@gmail.com> + + * backend/rust-compile-item.cc + (CompileItem::visit): Check canonical path of StaticItem + properly when name resolution 2.0 is enabled. + * resolve/rust-toplevel-name-resolver-2.0.cc + (TopLevel::visit): Insert static items into the value namespace. + +2025-03-19 Owen Avery <powerboat9.gamer@gmail.com> + + * ast/rust-expr.h + (InlineAsmOperand): Replace multiple mutually-exclusive tl::optional + fields with a std::unique_ptr and modify nested classes to allow + this. Also, make getters return references where possible. + * expand/rust-macro-builtins-asm.cc + (parse_reg_operand_out): Pass location when constructing + InlineAsmOperand. + +2025-03-19 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-toplevel-name-resolver-2.0.cc + (TopLevel::visit): Handle TypeAlias. + * resolve/rust-toplevel-name-resolver-2.0.h + (TopLevel::visit): Likewise. + +2025-03-19 Owen Avery <powerboat9.gamer@gmail.com> + + * typecheck/rust-hir-type-check-enumitem.cc: Add includes. + (TypeCheckEnumItem::visit): Fetch canonical paths properly when + name resolution 2.0 is enabled. + * typecheck/rust-hir-type-check-implitem.cc: Add includes. + (TypeCheckImplItem::visit): Fetch canonical paths properly when + name resolution 2.0 is enabled. + * typecheck/rust-hir-type-check-item.cc: Add include. + (TypeCheckItem::visit): Fetch canonical paths properly when name + resolution 2.0 is enabled. + +2025-03-19 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-finalize-imports-2.0.cc + (GlobbingVisitor::visit): Replace calls to insert_shadowable with + insert_globbed. + * resolve/rust-forever-stack.h + (ForeverStack::insert_globbed): Add. + * resolve/rust-forever-stack.hxx + (ForeverStack::insert_globbed): Add. + (ForeverStack::dfs): Handle modifications to Rib::Definition + fields. + * resolve/rust-late-name-resolver-2.0.cc + (Late::visit): Make IdentifierPattern-based declarations + shadowable. + * resolve/rust-name-resolution-context.cc + (NameResolutionContext::insert_globbed): Add. + * resolve/rust-name-resolution-context.h + (NameResolutionContext::insert_globbed): Add. + * resolve/rust-rib.cc + (Rib::Definition::Definition): Use Rib::Definition::Mode to + indicate shadowing mode instead of boolean, handle modifications + to Rib::Definition fields. + (Rib::Definition::is_ambiguous): Handle modifications to + Rib::Definition fields. + (Rib::Definition::to_string): Likewise. + (Rib::Definition::Shadowable): Handle changed constructor + signature. + (Rib::Definition::NonShadowable): Likewise. + (Rib::Definition::Globbed): Add. + (Rib::insert): Handle changes to Rib::Definition fields. + * resolve/rust-rib.h + (Rib::Definition::Globbed): Add. + (Rib::Definition::ids): Remove. + (Rib::Definition::ids_shadowable): Add. + (Rib::Definition::ids_non_shadowable): Add. + (Rib::Definition::ids_globbed): Add. + (Rib::Definition::get_node_id): Handle modifications to + Rib::Definition fields. + (Rib::Definition::Mode): Add. + (Rib::Definition::Definition): Use Rib::Definition::Mode to + indicate shadowing mode instead of boolean. + +2025-03-19 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-hir-trait-resolve.cc (TraitResolver::resolve_path_to_trait): + use error handling instead of assertion + * typecheck/rust-hir-type-check-item.cc (TypeCheckItem::visit): reuse trait reference + * typecheck/rust-hir-type-check-item.h: update prototype + +2025-03-19 Philip Herron <herron.philip@googlemail.com> + + * resolve/rust-ast-resolve-type.cc (ResolveTypeToCanonicalPath::visit): add unit-type catch + * resolve/rust-ast-resolve-type.h: likewise + +2025-03-19 Philip Herron <herron.philip@googlemail.com> + + * Make-lang.in: new objects + * ast/rust-ast-builder.cc (Builder::generic_type_path_segment): new helper + (Builder::single_generic_type_path): likewise + (Builder::new_type): likewise + (Builder::new_lifetime_param): likewise + (Builder::new_type_param): likewise + (Builder::new_lifetime): likewise + (Builder::new_generic_args): likewise + * ast/rust-ast-builder.h: new helper decls + * ast/rust-ast.h: new const getters + * ast/rust-path.h: likewise + * ast/rust-type.h: likewise + * expand/rust-derive-clone.cc (DeriveClone::clone_impl): take the types generics + (DeriveClone::visit_tuple): likewise + (DeriveClone::visit_struct): likewise + (DeriveClone::visit_union): likewise + * expand/rust-derive-clone.h: update header + * expand/rust-derive-copy.cc (DeriveCopy::copy_impl): similarly take type generics + (DeriveCopy::visit_struct): likewise + (DeriveCopy::visit_tuple): likewise + (DeriveCopy::visit_enum): likewise + (DeriveCopy::visit_union): likewise + * expand/rust-derive-copy.h: likewse + * ast/rust-ast-builder-type.cc: New file. + * ast/rust-ast-builder-type.h: New file. + +2025-03-19 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * rust-session-manager.cc (Session::expansion): Break on error after + top level name resolution. + +2025-03-19 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * resolve/rust-toplevel-name-resolver-2.0.cc (TopLevel::visit): Resolve + TypeParam. + * resolve/rust-toplevel-name-resolver-2.0.h: Add visit function + prototype. + +2025-03-19 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * ast/rust-ast.h: Node id getter could be const. + +2025-03-19 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * resolve/rust-late-name-resolver-2.0.h: Add visit function prototype. + * resolve/rust-late-name-resolver-2.0.cc (Late::visit): Change resolved + type segment. + +2025-03-19 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * resolve/rust-late-name-resolver-2.0.cc (Late::visit): Remove + assertion and explicitely tells why we ignore the insertion result. + +2025-03-19 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * Make-lang.in: Add new rust-bir-builder-pattern file. + * checks/errors/borrowck/rust-bir-builder-pattern.h: Remove + implementation. + * checks/errors/borrowck/rust-bir-builder-pattern.cc: New file. + +2025-03-19 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * ast/rust-ast-visitor.h: Make visit functions public. + +2025-03-19 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * resolve/rust-finalize-imports-2.0.h: Add parent member functions + from default resolver. + +2025-03-19 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * resolve/rust-default-resolver.cc (DefaultResolver::visit): Use + default visitor instead. + +2025-03-19 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * resolve/rust-default-resolver.cc (DefaultResolver::visit): Remove + default visit code and replace it with call to default visitor. + * resolve/rust-default-resolver.h: Remove removed function's + prototypes. + +2025-03-19 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * resolve/rust-default-resolver.cc (DefaultResolver::visit): Remove + empty visit function implementations. + * resolve/rust-default-resolver.h: Remove corresponding prototypes. + +2025-03-19 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * resolve/rust-default-resolver.h: Make most visit function override. + +2025-03-19 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * resolve/rust-early-name-resolver-2.0.cc (Early::Early): Add dirty + flag initialization. + (Early::go): Set dirty flag using top level resolver. + * resolve/rust-early-name-resolver-2.0.h: Add dirty flag. + * resolve/rust-toplevel-name-resolver-2.0.cc (TopLevel::TopLevel): + Initialize dirty flag. + (TopLevel::insert_or_error_out): Set dirty flag on successful + namespace modification. + * resolve/rust-toplevel-name-resolver-2.0.h: Add dirty flag. + * rust-session-manager.cc (Session::expansion): Modify fixed point + condition to include name resolution modifications. + +2025-03-19 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * resolve/rust-rib.cc (Rib::insert): Emit an error when trying to + insert an already inserted node. + +2025-03-19 Arthur Cohen <arthur.cohen@embecosm.com> + + * resolve/rust-early-name-resolver-2.0.h: New class for imports. + * resolve/rust-finalize-imports-2.0.cc (finalize_simple_import): Use + the new API. + (finalize_glob_import): Likewise. + (finalize_rebind_import): Likewise. + (FinalizeImports::FinalizeImports): Likewise. + (FinalizeImports::visit): Likewise. + * resolve/rust-finalize-imports-2.0.h: Likewise. + * resolve/rust-early-name-resolver-2.0.cc (Early::resolve_glob_import): Likewise. + (Early::resolve_simple_import): Likewise. + (Early::resolve_rebind_import): Likewise. + +2025-03-19 Arthur Cohen <arthur.cohen@embecosm.com> + + * resolve/rust-early-name-resolver-2.0.cc (Early::resolve_simple_import): + Insert import in all namespaces where they were resolved. + (Early::resolve_rebind_import): Likewise. + * resolve/rust-early-name-resolver-2.0.h: Improve APIs, make them + accept multiple resolutions. + * resolve/rust-finalize-imports-2.0.cc: Handle multiple resolutions. + * resolve/rust-name-resolution-context.h (resolve_path): Remove function. + +2025-03-19 Arthur Cohen <arthur.cohen@embecosm.com> + + * resolve/rust-early-name-resolver-2.0.cc (Early::visit_attributes): + Store errors for later. + +2025-03-19 Arthur Cohen <arthur.cohen@embecosm.com> + + * resolve/rust-finalize-imports-2.0.cc (FinalizeImports::go): Turn + static method into method. + (FinalizeImports::visit): New. + * resolve/rust-finalize-imports-2.0.h (class FinalizeImports): Make + FinalizeImports a visitor. + * resolve/rust-early-name-resolver-2.0.cc (Early::go): Use new FinalizeImports API. + (Early::resolve_glob_import): Use new API. + (Early::resolve_simple_import): Likewise. + (Early::resolve_rebind_import): Likewise. + (Early::build_import_mapping): Likewise. + * resolve/rust-early-name-resolver-2.0.h: Likewise. + * resolve/rust-toplevel-name-resolver-2.0.cc (TopLevel::visit): Likewise. + * resolve/rust-toplevel-name-resolver-2.0.h: Likewise. + +2025-03-19 Arthur Cohen <arthur.cohen@embecosm.com> + + * resolve/rust-late-name-resolver-2.0.cc (Late::visit): Add debug call. + * resolve/rust-toplevel-name-resolver-2.0.cc (TopLevel::visit): Store + imports using the new classes. + * resolve/rust-toplevel-name-resolver-2.0.h: Use new classes. + +2025-03-19 Arthur Cohen <arthur.cohen@embecosm.com> + + * resolve/rust-early-name-resolver-2.0.cc (Early::resolve_glob_import): + Use ImportData class. + (Early::resolve_simple_import): Likewise. + (Early::resolve_rebind_import): Likewise. + (Early::build_import_mapping): Likewise. + * resolve/rust-early-name-resolver-2.0.h: Likewise. + * resolve/rust-finalize-imports-2.0.cc (finalize_simple_import): Likewise. + (finalize_glob_import): Likewise. + (finalize_rebind_import): Likewise. + (FinalizeImports::go): Likewise. + * resolve/rust-finalize-imports-2.0.h: Likewise. + * resolve/rust-name-resolution-context.h: Likewise. + * resolve/rust-rib.h: Define ImportData class. + +2025-03-19 Arthur Cohen <arthur.cohen@embecosm.com> + + * Make-lang.in: Add new object file. + * ast/rust-item.h: Constify method. + * resolve/rust-early-name-resolver-2.0.cc (Early::go): Call into + the imports finalizer. + (Early::resolve_glob_import): Remove old resolution. + (Early::resolve_rebind_import): Likewise. + * resolve/rust-toplevel-name-resolver-2.0.cc (GlobbingVisitor::go): + New function. + (GlobbingVisitor::visit): Likewise. + (TopLevel::visit): Do not call into handle_use_* functions anymore. + * resolve/rust-toplevel-name-resolver-2.0.h (class GlobbingVisitor): + New. + * resolve/rust-finalize-imports-2.0.cc: New file. + * resolve/rust-finalize-imports-2.0.h: New file. + +2025-03-19 Arthur Cohen <arthur.cohen@embecosm.com> + + * resolve/rust-early-name-resolver-2.0.cc (Early::resolve_glob_import): New function. + (Early::resolve_simple_import): Likewise. + (Early::resolve_rebind_import): Likewise. + (Early::build_import_mapping): Likewise. + * resolve/rust-early-name-resolver-2.0.h: Add declarations and list of imports to + resolve. + * resolve/rust-toplevel-name-resolver-2.0.cc (TopLevel::handle_use_glob): Remove function, + which is now being handled by the Early name resolver. + (TopLevel::handle_use_dec): Likewise. + (TopLevel::handle_rebind): Likewise. + * resolve/rust-toplevel-name-resolver-2.0.h: Likewise, and add functions for creating + import list and fetching it. + +2025-03-19 Arthur Cohen <arthur.cohen@embecosm.com> + + * resolve/rust-toplevel-name-resolver-2.0.cc: Comment out handle_use + call and error emission. + * resolve/rust-toplevel-name-resolver-2.0.h: Create ImportKind class. + +2025-03-19 Arthur Cohen <arthur.cohen@embecosm.com> + + * resolve/rust-toplevel-name-resolver-2.0.cc (TopLevel::handle_use_dec): + Add notes on the problem. + * resolve/rust-toplevel-name-resolver-2.0.h: Likewise. + +2025-03-19 Arthur Cohen <arthur.cohen@embecosm.com> + + * resolve/rust-default-resolver.cc (DefaultResolver::visit): Do not + visit self's type if it does not have one. + +2025-03-19 Philip Herron <herron.philip@googlemail.com> + + * hir/rust-ast-lower-type.cc (ASTLowerQualifiedPathInType::visit): + check for valid as segment + +2025-03-19 Philip Herron <herron.philip@googlemail.com> + + * resolve/rust-ast-resolve-type.cc (ResolveType::visit): + handle never type + (ResolveTypeToCanonicalPath::visit): likewise + * resolve/rust-ast-resolve-type.h: missing never type + * resolve/rust-name-resolver.cc (Resolver::generate_builtins): + track never type node_id + (Resolver::setup_builtin): likewise + * resolve/rust-name-resolver.h: new never type getter + +2025-03-19 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-default-resolver.cc + (DefaultResolver::visit): Remove some empty overloads which + DefaultASTVisitor::visit should be able to handle. + * resolve/rust-default-resolver.h + (DefaultResolver::visit): Likewise. + +2025-03-19 Owen Avery <powerboat9.gamer@gmail.com> + + * util/optional.h + (optional): Add assertions to dereference operator overloads + when C++14 is available. + +2025-03-19 Marc Poulhiès <dkm@kataplop.net> + + * hir/rust-hir-dump.cc (Dump::visit): Add missing fields. + +2025-03-19 Philip Herron <herron.philip@googlemail.com> + + * hir/rust-ast-lower-item.cc (ASTLoweringItem::visit): the polarity was reversed + * typecheck/rust-hir-type-check-item.cc: check the polarity + +2025-03-19 benjamin.thos <benjamin.thos@epita.fr> + + * resolve/rust-ast-resolve-expr.cc (ResolveExpr::visit): Add + implementation of error propagation visitor + * resolve/rust-ast-resolve-expr.h: Add prototype of error + propagation + +2025-03-19 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * resolve/rust-late-name-resolver-2.0.cc (Late::visit): Add optional + check. + +2025-03-19 JoanVC <github-91yu@joanvc.cat> + + * backend/rust-compile-expr.cc + +2025-03-19 JoanVC <github-91yu@joanvc.cat> + + * backend/rust-compile-expr.cc: Fix range checking for both integers and floats. + * hir/tree/rust-hir-expr.h: Add "negative_number" boolean to LiteralExpr class. + +2025-03-19 Arthur Cohen <arthur.cohen@embecosm.com> + + * rust-session-manager.cc (Session::compile_crate): Use less repetition, + fix a typo in `reports`, fix word order. + +2025-03-19 benjamin.thos <benjamin.thos@epita.fr> + + * checks/errors/rust-feature-gate.cc (FeatureGate::visit): Emit error + on trait when auto field member true. + * checks/errors/rust-feature-gate.h: add prototype of trait visitor. + * checks/errors/rust-feature.cc (Feature::create): add + optin_builtin_traits in match of feature. + +2025-03-19 Raiki Tamura <tamaron1203@gmail.com> + + * Make-lang.in: Add rust-hir-pattern-analysis.o. + * rust-session-manager.cc (Session::compile_crate): + Add pattern analysis pass. + * typecheck/rust-hir-type-check-pattern.cc (TypeCheckPattern::visit): + Do typecheck for subpatterns. + * checks/errors/rust-hir-pattern-analysis.cc: New file. + * checks/errors/rust-hir-pattern-analysis.h: New file. + +2025-03-19 Liam Naddell <liam.naddell@mail.utoronto.ca> + + * backend/rust-compile.cc: + Modify compute_address_for_trait_item to support supertraits + * typecheck/rust-tyty.cc: + Remove auto + +2025-03-19 Kushal Pal <kushalpal109@gmail.com> + + * checks/errors/borrowck/rust-bir-dump.cc (Dump::go): Use strong + type instead of size_t. + (Dump::visit_place): Likewise. + (Dump::visit_scope): Likewise. + * checks/errors/borrowck/rust-bir-dump.h (class Dump): Use + IndeVec for place_map. + +2025-03-19 Kushal Pal <kushalpal109@gmail.com> + + * checks/errors/borrowck/rust-bir-dump.cc (simplify_cfg): + Used `IndexVec` for bb_fold_map. + (Dump::go): Use strong type as index instead of value as now we + are using `IndexVec`. + (Dump::visit): Likewise. + * checks/errors/borrowck/rust-bir-dump.h (class Dump): Use + `IndexVec` for bb_fold_map. + * checks/errors/borrowck/rust-bir-place.h: Add constructor for + `IndexVec` that can reserve size. + +2025-03-19 Kushal Pal <kushalpal109@gmail.com> + + * checks/errors/borrowck/rust-bir-place.h: Use strong types as + index. + +2025-03-19 Kushal Pal <kushalpal109@gmail.com> + + * checks/errors/borrowck/rust-bir-builder-expr-stmt.cc + (ExprStmtBuilder::visit): Use strong type as index and + remove access to numeric value. + * checks/errors/borrowck/rust-bir-builder-internal.h + (struct BuilderContext): Likewise. + * checks/errors/borrowck/rust-bir-dump.cc (simplify_cfg): + Likewise. + (Dump::go): Likewise. + (Dump::visit): Likewise. + * checks/errors/borrowck/rust-bir-fact-collector.h + (class FactCollector): Likewise. + (points): Likewise. + * checks/errors/borrowck/rust-bir.h (struct BasicBlockId): Used + IndexVec for BasicBlocks. + (struct Function): Likewise. + * checks/errors/borrowck/rust-borrow-checker-diagnostics.cc + (BorrowCheckerDiagnostics::get_statement): Change the extracted + index to strong type. + +2025-03-19 Kushal Pal <kushalpal109@gmail.com> + + * checks/errors/borrowck/rust-bir-place.h: Used `IndexVec` with + ScopeId as index. + * checks/errors/borrowck/rust-borrow-checker-diagnostics.cc + (BorrowCheckerDiagnostics::get_loan): Convert Polonius::Loan to + BIR::Loan, so we can use it as index. + +2025-03-19 Kushal Pal <kushalpal109@gmail.com> + + * checks/errors/borrowck/rust-bir-place.h: + Used `IndexVec` with ScopeId as index. + +2025-03-19 Kushal Pal <kushalpal109@gmail.com> + + * checks/errors/borrowck/rust-bir-place.h (struct Loan): + Introduce new class `IndexVec` inspired from IndexVec of rust. + It acts as a wrapper around `std::vector` and lets user specify + a strong type to use as index. + +2025-03-19 Kushal Pal <kushalpal109@gmail.com> + + * checks/errors/borrowck/rust-bir-builder-expr-stmt.cc (ExprStmtBuilder::visit): + Use value of BasicBlockId as index. + * checks/errors/borrowck/rust-bir-builder-internal.h (struct BuilderContext): + Likewise. + * checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h: + Initialize with ENTRY_BASIC_BLOCK. + * checks/errors/borrowck/rust-bir-dump.cc (simplify_cfg): + Use value of BasicBlockId as index. + (Dump::go): Likewise. + (Dump::visit): Likewise. + * checks/errors/borrowck/rust-bir-fact-collector.h (class FactCollector): + Initialize with ENTRY_BASIC_BLOCK. + (points): Use value of BasicBlockId as index. + * checks/errors/borrowck/rust-bir.h (struct BasicBlockId): + BasicBlockId is a struct now. + +2025-03-19 Kushal Pal <kushalpal109@gmail.com> + + * checks/errors/borrowck/rust-bir-builder-expr-stmt.cc + (ExprStmtBuilder::setup_loop): Use value of ScopeId. + (ExprStmtBuilder::visit): Use continue scope id instead of + continue basic block id. + * checks/errors/borrowck/rust-bir-builder-internal.h: Use value + of ScopeId. + * checks/errors/borrowck/rust-bir-dump.cc (Dump::go): Use + ROOT_VALUE instead of hardcoded 0. + (Dump::visit_scope): Use value of ScopeId. + * checks/errors/borrowck/rust-bir-place.h (struct ScopeId): + ScopeId is now a struct. + (std::numeric_limits::max): Set invalid ScopeId. + +2025-03-19 Kushal Pal <kushalpal109@gmail.com> + + * checks/errors/borrowck/rust-bir-dump.cc (Dump::visit): Use new + API, i.e get_loan_id() instead of get_loan(). + * checks/errors/borrowck/rust-bir-fact-collector.h (points): Use + value of LoanId in Polonius facts. + * checks/errors/borrowck/rust-bir-place.h (struct LoanId): + LoanId is a struct now. + * checks/errors/borrowck/rust-bir.h (class AbstractExpr): Use + new API, as we are getting a LoanId and not a loan itself. + +2025-03-19 Kushal Pal <kushalpal109@gmail.com> + + * checks/errors/borrowck/rust-bir-builder-internal.h: Use + FreeRegions instead of making a temporary vector of FreeRegion. + * checks/errors/borrowck/rust-bir-builder.h: Likewise. + * checks/errors/borrowck/rust-bir-fact-collector.h (class FactCollector): + Likewise. + (points): Likewise. + * checks/errors/borrowck/rust-bir-free-region.h: Remove obsolete + set_from() helpers, add push_back(). + * checks/errors/borrowck/rust-bir-place.h: Use FreeRegions + instead of making a temporary vector of Origin. + * typecheck/rust-tyty-variance-analysis-private.h: Change type + of `regions`. + * typecheck/rust-tyty-variance-analysis.cc (CrateCtx::query_type_regions): + Use new type. + (GenericTyPerCrateCtx::query_generic_variance): Likewise. + (TyVisitorCtx::add_constraints_from_generic_args): Likewise. + (FieldVisitorCtx::add_constraints_from_region): Likewise. + (FieldVisitorCtx::add_constrints_from_param): Likewise. + * typecheck/rust-tyty-variance-analysis.h: Likewise. + +2025-03-19 Kushal Pal <kushalpal109@gmail.com> + + * checks/errors/borrowck/rust-bir-builder-internal.h: Use + STATIC_FREE_REGION, use value of FreeRegion for origin. + * checks/errors/borrowck/rust-bir-builder.h: Use free region + value. + * checks/errors/borrowck/rust-bir-dump.cc (Dump::visit_scope): + Likewise. + * checks/errors/borrowck/rust-bir-fact-collector.h (points): + Likewise. + * checks/errors/borrowck/rust-bir-free-region.h (struct FreeRegion): + Make FreeRegion a struct. + * checks/errors/borrowck/rust-bir-place.h: Use FreeRegion + instead of Origin in PlaceDB. + * typecheck/rust-tyty-variance-analysis.cc (FieldVisitorCtx::add_constraints_from_region): + Use value of FreeRegion for origin. + (FieldVisitorCtx::add_constrints_from_param): Likewise. + (Term::make_transform): Likewise. + +2025-03-19 Kushal Pal <kushalpal109@gmail.com> + + * checks/errors/borrowck/rust-bir-dump.cc (renumber_places): + Use value of PlaceId as index. + (Dump::visit_place): Likewise. + (Dump::visit_scope): Likewise. + (Dump::go): Refill `place_map` with for loop instead of + using std::iota(). + * checks/errors/borrowck/rust-bir-fact-collector.h (points): Use + value as index. + * checks/errors/borrowck/rust-bir-place.h (struct PlaceId): + PlaceId is now a class holding a uint32_t value. Overloaded + comparision operators for easier comparision. + +2025-03-19 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-ast-resolve-pattern.cc + (PatternDeclaration::check_bindings_consistency): Check if + outer_bindings_map contains an entry before indexing. + +2025-03-19 Owen Avery <powerboat9.gamer@gmail.com> + + * util/rust-canonical-path.h + (CanonicalPath::CanonicalPath): Properly initialize crate_num + with copy constructor. + +2025-03-19 badumbatish <tanghocle456@gmail.com> + + * backend/rust-compile-asm.cc (CompileAsm::visit): + Change API, public/private, comments, formatting from code + review + (CompileAsm::asm_build_expr): Likewise. + (CompileAsm::tree_codegen_asm): Likewise. + * backend/rust-compile-asm.h (class CompileAsm): Likewise. + * backend/rust-compile-expr.cc (CompileExpr::visit): Likewise. + * checks/errors/privacy/rust-privacy-reporter.cc (PrivacyReporter::visit): Likewise. + * expand/rust-macro-builtins-asm.cc (strip_double_quotes): Likewise. + (parse_options): Likewise. + (parse_asm_arg): Likewise. + (expand_inline_asm_strings): Likewise. + (parse_asm): Likewise. + * expand/rust-macro-builtins-asm.h (strip_double_quotes): Likewise. + (expand_inline_asm_strings): Likewise. + (expand_inline_asm_string): Likewise. + * hir/tree/rust-hir-expr.h: Likewise. + +2025-03-19 badumbatish <tanghocle456@gmail.com> + + * backend/rust-compile-asm.cc (CompileAsm::asm_build_expr): + Remove debug + * expand/rust-macro-builtins-asm.cc (expand_inline_asm_strings): + properly formatted via rust instead of c + (parse_asm): formatted comment + (parse_format_strings): formatted comment + * hir/tree/rust-hir-expr.h: fix is_simple_asm() + +2025-03-19 badumbatish <tanghocle456@gmail.com> + + * backend/rust-compile-asm.cc (CompileAsm::asm_build_expr): + Use's array type when constring string tree + (CompileAsm::asm_construct_string_tree): + Use's array type when constring string tree + +2025-03-19 badumbatish <tanghocle456@gmail.com> + + * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit): + Added noreturn checking for nevertype + +2025-03-19 badumbatish <tanghocle456@gmail.com> + + * backend/rust-compile-asm.cc (CompileAsm::asm_build_expr): + Add debug comment + (CompileAsm::asm_construct_outputs): + Perform lowering hir output operand to tree + +2025-03-19 badumbatish <tanghocle456@gmail.com> + + * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit): + Perform type check on InlineAsm's operand + (typecheck_inline_asm_operand): Likewise + +2025-03-19 badumbatish <tanghocle456@gmail.com> + + * backend/rust-compile-asm.cc (CompileAsm::asm_construct_outputs): + Lower the HIR to tree with CompileExpr + * backend/rust-compile-asm.h: Remove static from method + +2025-03-19 badumbatish <tanghocle456@gmail.com> + + * backend/rust-compile-asm.cc (strip_double_quotes): + Move strip double quotes to parse phase + (CompileAsm::asm_construct_string_tree): Likewise + * backend/rust-compile-asm.h (strip_double_quotes): Likewise + * expand/rust-macro-builtins-asm.cc (strip_double_quotes): + Likewise + (expand_inline_asm): Renamed to expand_inline_asm_strings + (expand_inline_asm_strings): Renamed from expand_inline_asm + (parse_asm): Move strip double quotes to parse phase + (parse_format_strings): Likewise + * expand/rust-macro-builtins-asm.h (strip_double_quotes): + Likewise + (expand_inline_asm_strings): Inline asm expansion fn + (expand_inline_asm_string): Inline asm expansion fn + +2025-03-19 badumbatish <tanghocle456@gmail.com> + + * expand/rust-macro-builtins-asm.cc (parse_reg_operand): + Remove warnings + (parse_reg_operand_out): Remove warnings + (expand_inline_asm): New function for eventual expansion + (parse_asm): Use expand_inline_asm + +2025-03-19 badumbatish <tanghocle456@gmail.com> + + * backend/rust-compile-asm.cc (CompileAsm::asm_construct_outputs): + Set up counting to check + +2025-03-19 badumbatish <tanghocle456@gmail.com> + + * backend/rust-compile-asm.cc (CompileAsm::asm_build_expr): + Use expr's is_simple_asm and is_inline_asm + (CompileAsm::asm_is_simple): removed + (CompileAsm::asm_is_inline): removed + * backend/rust-compile-asm.h: Add docs to ASM_TREE_ARRAY_LENGTH + * hir/tree/rust-hir-expr.h: Add is_simple_asm, is_inline_asm + and remove #include tree + +2025-03-19 badumbatish <tanghocle456@gmail.com> + + * backend/rust-compile-asm.cc (strip_double_quotes): + Refactor compile-asm for first round review + (CompileAsm::asm_build_asm_stmt): Likewise. + (CompileAsm::asm_build_expr): Likewise. + (CompileAsm::asm_get_locus): Likewise. + (CompileAsm::asm_construct_string_tree): Likewise. + (CompileAsm::asm_construct_outputs): Likewise. + (CompileAsm::asm_construct_inputs): Likewise. + (CompileAsm::asm_construct_clobber_tree): Likewise. + (CompileAsm::asm_construct_label_tree): Likewise. + (CompileAsm::asm_is_simple): Likewise. + (CompileAsm::asm_is_inline): Likewise. + * backend/rust-compile-asm.h (strip_double_quotes): Likewise. + (class CompileAsm): Likewise. + +2025-03-19 badumbatish <tanghocle456@gmail.com> + + * backend/rust-compile-asm.cc (CompileAsm::add_stmt): + Deleted + (CompileAsm::CompileAsm): + Successfully produce pseudo-nop + (CompileAsm::visit): Likewise + (CompileAsm::asm_build_asm_stmt): Likewise + (CompileAsm::asm_construct_string_tree): Likewise + (CompileAsm::asm_is_inline): Likewise + * backend/rust-compile-asm.h (class CompileAsm): Likewise + * backend/rust-compile-expr.cc (CompileExpr::visit): Likewise + +2025-03-19 badumbatish <tanghocle456@gmail.com> + + * backend/rust-compile-asm.cc (CompileAsm::add_stmt): + Scaffolding code. + (CompileAsm::asm_build_asm_stmt): Likewise. + (CompileAsm::asm_build_expr): Likewise. + (CompileAsm::asm_construct_string_tree): Likewise. + * backend/rust-compile-asm.h: Likewise. + * backend/rust-compile-expr.cc (CompileExpr::visit): Likewise. + +2025-03-19 badumbatish <tanghocle456@gmail.com> + + * Make-lang.in: + Scaffolding new compile-asm files + * backend/rust-compile-expr.cc (CompileExpr::visit): Likewise + * hir/tree/rust-hir-expr.h: Likewise + * backend/rust-compile-asm.cc: New file. Likewise + * backend/rust-compile-asm.h: New file. Likewise + +2025-03-19 jjasmine <tanghocle456@gmail.com> + + * backend/rust-compile-expr.cc (CompileExpr::visit): + Setting up interfaces for codegen + * hir/tree/rust-hir-expr.h: Likewise. + +2025-03-19 jjasmine <tanghocle456@gmail.com> + + * backend/rust-compile-expr.cc (CompileExpr::visit): + Local testing for build_string and debug() + +2025-03-19 jjasmine <tanghocle456@gmail.com> + + * hir/tree/rust-hir.cc (InlineAsm::accept_vis): + Make sure CompileExpr::visit is reached + * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit): + Likewise + +2025-03-19 jjasmine <tanghocle456@gmail.com> + + * backend/rust-compile-block.h: + Scaffolding asm codegen + * backend/rust-compile-expr.cc (CompileExpr::visit): Likewise. + * backend/rust-compile-expr.h: Likewise. + * checks/errors/borrowck/rust-bir-builder-expr-stmt.cc (ExprStmtBuilder::visit): Likewise. + * checks/errors/borrowck/rust-bir-builder-expr-stmt.h: Likewise. + * checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h: Likewise. + * checks/errors/privacy/rust-privacy-reporter.cc (PrivacyReporter::visit): Likewise. + * checks/errors/privacy/rust-privacy-reporter.h: Likewise. + * hir/tree/rust-hir-expr.h: Likewise. + * hir/tree/rust-hir-visitor.h: Likewise. + * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit): Likewise. + * typecheck/rust-hir-type-check-expr.h: Likewise. + +2025-03-19 badumbatish <tanghocle456@gmail.com> + + * expand/rust-macro-builtins-asm.cc (parse_reg_operand): + Fix parsing logic & reassignment logic + (parse_reg_operand_in): Fix parsing + (parse_reg_operand_out): Fix parsing + (parse_reg_operand_inout): Fix parsing + (parse_reg_operand_unexpected): Remove rust_unreachable() + (parse_asm_arg): Fix parsing logic + +2025-03-19 badumbatish <tanghocle456@gmail.com> + + * typecheck/rust-hir-type-check.h: + Add pop guard for binder + +2025-03-19 badumbatish <tanghocle456@gmail.com> + + * resolve/rust-ast-resolve.cc (NameResolution::go): + Fix warnings from const auto& to const auto + +2025-03-19 Raiki Tamura <tamaron1203@gmail.com> + + * lex/rust-lex.cc (Lexer::build_token): Emit error code. + * lex/rust-lex.h: Fix comment. + +2025-03-19 Raiki Tamura <tamaron1203@gmail.com> + + * hir/tree/rust-hir.cc (Item::item_kind_string): New function. + * hir/tree/rust-hir.h: New function. + * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit): + Modify to check all arms in match expressions even if some of them + has errors. + * typecheck/rust-hir-type-check-pattern.cc (TypeCheckPattern::visit): + Add and fix check for path patterns. + +2025-03-19 Raiki Tamura <tamaron1203@gmail.com> + + * typecheck/rust-hir-type-check-pattern.cc (TypeCheckPattern::visit): + Add check for union patterns. + +2025-03-19 Arthur Cohen <arthur.cohen@embecosm.com> + + * checks/errors/rust-feature.cc (Feature::create): Reuse variable, + remove now optional parameters from constructor. + * checks/errors/rust-feature.h: Cleanup class definition. + * checks/errors/rust-feature-gate.cc (FeatureGate::gate): Use optional. + * checks/errors/rust-feature-gate.h: Cleanup visitor implementation. + * checks/errors/borrowck/ffi-polonius/Cargo.lock: New file. + +2025-03-19 Arthur Cohen <arthur.cohen@embecosm.com> + + * checks/errors/rust-feature-gate.cc (FeatureGate::visit): Add base + feature gating for `#[feature(prelude_import)]`. + * checks/errors/rust-feature-gate.h: Likewise. + * checks/errors/rust-feature.cc (Feature::create): Likewise. + * checks/errors/rust-feature.h: Likewise. + * util/rust-attribute-values.h: Add base handling for `#[prelude_import]` + attribute. + * util/rust-attributes.cc: Likewise. + +2025-03-19 badumbatish <tanghocle456@gmail.com> + + * ast/rust-ast-full-decls.h (struct InlineAsmOperand): + Change to class + (class InlineAsmOperand): Change from struct + * hir/tree/rust-hir-full-decls.h (struct InlineAsmRegOrRegClass): + Removed from decl, used from AST + (struct AnonConst): new decl from rust-hir-expr.h + (class InlineAsmOperand): new decl from rust-hir-expr.h + +2025-03-19 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-ast-full-decls.h (class PathPattern): Rename PathPattern to... + (class Path): ...Path + * ast/rust-ast-collector.cc (TokenCollector::visit): Add required methods + for LangItemPath and RegularPath. + * ast/rust-ast-collector.h: Likewise. + * ast/rust-ast-visitor.cc (DefaultASTVisitor::visit): Likewise. + * ast/rust-ast-visitor.h: Likewise. + * ast/rust-path.cc (PathPattern::as_string): Likewise. + (RegularPath::as_string): Likewise. + (LangItemPath::as_string): Likewise. + (PathPattern::convert_to_simple_path): Likewise. + (RegularPath::convert_to_simple_path): Likewise. + (RegularPath::accept_vis): Likewise. + (LangItemPath::accept_vis): Likewise. + (PathInExpression::as_string): Likewise. + (QualifiedPathInExpression::as_string): Likewise. + * ast/rust-path.h (class PathPattern): Likewise. + (class Path): Likewise. + (class RegularPath): Likewise. + (class LangItemPath): Likewise. + (class PathInExpression): Likewise. + (class QualifiedPathInExpression): Likewise. + * ast/rust-pattern.h (class PathPattern): Likewise. + (class Path): Likewise. + * expand/rust-derive.h: Likewise. + * hir/rust-ast-lower-base.cc (ASTLoweringBase::visit): Likewise. + * hir/rust-ast-lower-base.h: Likewise. + * resolve/rust-ast-resolve-base.cc (ResolverBase::visit): Likewise. + * resolve/rust-ast-resolve-base.h: Likewise. + +2025-03-19 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-ast.h (class PathExpr): Remove class. + * ast/rust-path.h (class PathInExpression): Inherit from ExprWithoutBlock. + (class QualifiedPathInExpression): Likewise. + +2025-03-19 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-path.h (class PathInExpression): Remove `remove_all_segments` + method, add a `marked_for_strip` flag instead. + +2025-03-19 Muhammad Mahad <mahadtxt@gmail.com> + + * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit): + Add error code and update error message + +2025-03-19 Kushal Pal <kushalpal109@gmail.com> + + * checks/errors/borrowck/rust-borrow-checker-diagnostics.cc + (BorrowCheckerDiagnostics::report_move_errors): Specify + locations for code causing errors and related moves. + +2025-03-19 Kushal Pal <kushalpal109@gmail.com> + + * checks/errors/borrowck/rust-borrow-checker-diagnostics.cc + (BorrowCheckerDiagnostics::report_subset_errors): Highlight + lifetime locations while reporting subset errors. + (BorrowCheckerDiagnostics::get_lifetime_param): Helper function + to fetch HIR::Lifetime node from Polonius::Origin. + * checks/errors/borrowck/rust-borrow-checker-diagnostics.h: + Definition of helper function. + +2025-03-19 Kushal Pal <kushalpal109@gmail.com> + + * checks/errors/borrowck/rust-bir-builder.h: Map regions to + their respective HIR nodes. + * checks/errors/borrowck/rust-bir.h (struct Function): + Add unordered_map to maintain the mapping. + +2025-03-19 Liam Naddell <liam.naddell@mail.utoronto.ca> + + * typecheck/rust-hir-type-check-pattern.cc: + Emit E0532 when trying to reference a Tuple or Struct variant + using a non Tuple or Struct pattern. + +2025-03-19 Liam Naddell <liam.naddell@mail.utoronto.ca> + + * expand/rust-expand-visitor.h: + remove auto keyword + * expand/rust-macro-builtins-helpers.cc: + allow for changing macro invoc types on eager expansions to + semicoloned macros + * expand/rust-macro-builtins-helpers.h: + add default semicoloned argument + * expand/rust-macro-builtins-include.cc: + allow for eager expansion for include and include_bytes + allow for parsing include invocations as items instead of + expressions, which allows invocations at global scope + * expand/rust-macro-expand.cc: + push Expr type for eager invocations + +2025-03-19 Kushal Pal <kushalpal109@gmail.com> + + * checks/errors/borrowck/rust-bir-builder-internal.h: + Use `make_*` functions to create BIR::Statements. + * checks/errors/borrowck/rust-bir.h: Make a complete constructor + and introduce `make_*` functions to create various + BIR::Statements. + +2025-03-19 Kushal Pal <kushalpal109@gmail.com> + + * checks/errors/borrowck/rust-borrow-checker-diagnostics.cc + (BorrowCheckerDiagnostics::report_loan_errors): Add label to + where the borrow occurs and where the invalid access occurs. + (BorrowCheckerDiagnostics::get_statement): + Fetch BIR::Statement from Polonius::Point + (BorrowCheckerDiagnostics::get_loan): + Fetch BIR::Loan from Polonius::Loan + * checks/errors/borrowck/rust-borrow-checker-diagnostics.h: + Function definition of helpers. + +2025-03-19 Kushal Pal <kushalpal109@gmail.com> + + * checks/errors/borrowck/rust-bir-builder-expr-stmt.cc (ExprStmtBuilder::visit): + Add location parameter. + * checks/errors/borrowck/rust-bir-builder.h: Likewise. + * checks/errors/borrowck/rust-bir-builder-internal.h: Add helper + function for pushing return statements. + * checks/errors/borrowck/rust-bir.h: Remove `expr` parameter as + it is only needed for ASSIGNMENT statements, for which we + already have a constructor. + +2025-03-19 badumbatish <tanghocle456@gmail.com> + + * resolve/rust-ast-resolve-expr.cc (ResolveExpr::visit): + Implement resolve expr for inline asm ast + (translate_operand): Likewise. + * resolve/rust-ast-resolve-expr.h: Likewise. + +2025-03-19 Kushal Pal <kushalpal109@gmail.com> + + * checks/errors/borrowck/rust-bir-builder-internal.h: + Fill location for loan. + * checks/errors/borrowck/rust-bir-place.h (struct Loan): + Add location field. + +2025-03-19 Kushal Pal <kushalpal109@gmail.com> + + * checks/errors/borrowck/rust-bir-builder-expr-stmt.cc + (ExprStmtBuilder::visit): Added location parameter. + * checks/errors/borrowck/rust-bir-builder-internal.h: Likewise. + * checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h: + Likewise. + * checks/errors/borrowck/rust-bir-builder-pattern.h: Likewise. + * checks/errors/borrowck/rust-bir-builder.h: Likewise. + * checks/errors/borrowck/rust-bir.h: Likewise. + +2025-03-19 badumbatish <tanghocle456@gmail.com> + + * hir/rust-ast-lower-expr.cc (translate_operand_in): + Turn to switch case, use new helper functions + (translate_operand_out): Likewise. + (translate_operand_inout): Likewise. + (translate_operand_split_in_out): Likewise. + (translate_operand_const): Likewise. + (translate_operand_sym): Likewise. + (translate_operand_label): Likewise. + (from_operand): Likewise. + (ASTLoweringExpr::visit): Likewise. + +2025-03-19 badumbatish <tanghocle456@gmail.com> + + * hir/rust-ast-lower-expr.cc (from_operand): + Set up the lowering for operand + (ASTLoweringExpr::visit): Likewise + * hir/tree/rust-hir-expr.h (struct InlineAsmRegOrRegClass): + Not necessary, kept from ast + (struct AnonConst): Set up lowering for operand + (class InlineAsmOperand): Likewise, add getters + +2025-03-19 Kushal Pal <kushalpal109@gmail.com> + + * checks/errors/borrowck/polonius/rust-polonius.h (struct FullPoint): + Added comments and made extraction of statement more verbose for + better understanding. + * checks/errors/borrowck/ffi-polonius/src/lib.rs: Likewise. + +2025-03-19 badumbatish <tanghocle456@gmail.com> + + * ast/rust-expr.h (struct InlineAsmOperand): changed to class + (class InlineAsmOperand): Have appropriate constructor, + and getter + * expand/rust-macro-builtins-asm.cc (parse_reg_operand): + Use the new implement constructors and new control flow. + (parse_reg_operand_in): Likewise + (parse_reg_operand_out): Likewise + (parse_reg_operand_inout): Likewise + (parse_reg_operand_const): Likewise + +2025-03-19 badumbatish <tanghocle456@gmail.com> + + * ast/rust-expr.h (struct InlineAsmOperand): + Add construction for register_type + * expand/rust-macro-builtins-asm.cc (parse_reg_operand): + Fix parsing logic & reassignment logic + (parse_reg_operand_in): Fix parsing + (parse_reg_operand_out): Fix parsing + (parse_reg_operand_inout): Fix parsing + (parse_reg_operand_unexpected): Remove rust_unreachable() + (parse_asm_arg): Fix parsing logic + * expand/rust-macro-builtins-asm.h: Add = operator overloading + +2025-03-19 Kushal Pal <kushalpal109@gmail.com> + + * checks/errors/borrowck/polonius/rust-polonius.h (struct FullPoint): + This is the correct way of extracting the required bits. + +2025-03-19 Arthur Cohen <arthur.cohen@embecosm.com> + + * checks/errors/borrowck/ffi-polonius/src/gccrs_ffi.rs: Remove extern + type feature. + * checks/errors/borrowck/ffi-polonius/src/lib.rs: Define FFIVector + per the nomicon's recommendation + https://doc.rust-lang.org/nomicon/ffi.html#representing-opaque-structs + +2025-03-19 Liam Naddell <liam.naddell@mail.utoronto.ca> + + * ast/rust-ast.cc: + Fix Attribute constructors to copy inner_attribute + * checks/errors/rust-unsafe-checker.cc: + Add pass for #[may_dangle] in safe impl's + * hir/rust-ast-lower-item.cc: + Add support for unsafe impl's + * hir/rust-ast-lower-type.cc: + Lower attributes in impl's from AST to HIR + * hir/rust-hir-dump.cc: + Change single attribute to AttrVec + * hir/tree/rust-hir-item.h: + Add unsafe support to Impl blocks in HIR + * hir/tree/rust-hir.cc: + Change single attribute to AttrVec + * hir/tree/rust-hir.h: + Add has/get_outer_attribute to GenericParam + +2025-03-19 Antonio Gomes <antoniospg100@gmail.com> + + * expand/rust-cfg-strip.cc: + Strip struct expr fields and strip fields in struct definition + * expand/rust-cfg-strip.h: + Signatures for new function maybe_strip_struct_expr_fields + +2025-03-18 Marc Poulhiès <dkm@kataplop.net> + + PR rust/119333 + * Make-lang.in: Force offline mode for cargo + +2025-03-18 Arthur Cohen <arthur.cohen@embecosm.com> + + * checks/errors/borrowck/ffi-polonius/.cargo/config.toml: New file, force vendored deps. + * checks/errors/borrowck/ffi-polonius/vendor/datafrog/.cargo-checksum.json: New file. + * checks/errors/borrowck/ffi-polonius/vendor/datafrog/CODE_OF_CONDUCT.md: New file. + * checks/errors/borrowck/ffi-polonius/vendor/datafrog/Cargo.toml: New file. + * checks/errors/borrowck/ffi-polonius/vendor/datafrog/LICENSE-APACHE: New file. + * checks/errors/borrowck/ffi-polonius/vendor/datafrog/LICENSE-MIT: New file. + * checks/errors/borrowck/ffi-polonius/vendor/datafrog/README.md: New file. + * checks/errors/borrowck/ffi-polonius/vendor/datafrog/RELEASES.md: New file. + * checks/errors/borrowck/ffi-polonius/vendor/datafrog/examples/borrow_check.rs: New file. + * checks/errors/borrowck/ffi-polonius/vendor/datafrog/examples/graspan1.rs: New file. + * checks/errors/borrowck/ffi-polonius/vendor/datafrog/src/join.rs: New file. + * checks/errors/borrowck/ffi-polonius/vendor/datafrog/src/lib.rs: New file. + * checks/errors/borrowck/ffi-polonius/vendor/datafrog/src/map.rs: New file. + * checks/errors/borrowck/ffi-polonius/vendor/datafrog/src/test.rs: New file. + * checks/errors/borrowck/ffi-polonius/vendor/datafrog/src/treefrog.rs: New file. + * checks/errors/borrowck/ffi-polonius/vendor/log/.cargo-checksum.json: New file. + * checks/errors/borrowck/ffi-polonius/vendor/log/CHANGELOG.md: New file. + * checks/errors/borrowck/ffi-polonius/vendor/log/Cargo.toml: New file. + * checks/errors/borrowck/ffi-polonius/vendor/log/LICENSE-APACHE: New file. + * checks/errors/borrowck/ffi-polonius/vendor/log/LICENSE-MIT: New file. + * checks/errors/borrowck/ffi-polonius/vendor/log/README.md: New file. + * checks/errors/borrowck/ffi-polonius/vendor/log/benches/value.rs: New file. + * checks/errors/borrowck/ffi-polonius/vendor/log/src/__private_api.rs: New file. + * checks/errors/borrowck/ffi-polonius/vendor/log/src/kv/error.rs: New file. + * checks/errors/borrowck/ffi-polonius/vendor/log/src/kv/key.rs: New file. + * checks/errors/borrowck/ffi-polonius/vendor/log/src/kv/mod.rs: New file. + * checks/errors/borrowck/ffi-polonius/vendor/log/src/kv/source.rs: New file. + * checks/errors/borrowck/ffi-polonius/vendor/log/src/kv/value.rs: New file. + * checks/errors/borrowck/ffi-polonius/vendor/log/src/lib.rs: New file. + * checks/errors/borrowck/ffi-polonius/vendor/log/src/macros.rs: New file. + * checks/errors/borrowck/ffi-polonius/vendor/log/src/serde.rs: New file. + * checks/errors/borrowck/ffi-polonius/vendor/log/triagebot.toml: New file. + * checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/.cargo-checksum.json: New file. + * checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/Cargo.toml: New file. + * checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/README.md: New file. + * checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/facts.rs: New file. + * checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/lib.rs: New file. + * checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/output/datafrog_opt.rs: + New file. + * checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/output/initialization.rs: + New file. + * checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/output/liveness.rs: + New file. + * checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/output/location_insensitive.rs: + New file. + * checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/output/mod.rs: New file. + * checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/output/naive.rs: New file. + * checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/.cargo-checksum.json: New file. + * checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/CODE_OF_CONDUCT.md: New file. + * checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/Cargo.toml: New file. + * checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/LICENSE-APACHE: New file. + * checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/LICENSE-MIT: New file. + * checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/README.md: New file. + * checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/src/lib.rs: New file. + 2025-03-17 Muhammad Mahad <mahadtxt@gmail.com> * typecheck/rust-hir-type-check-type.cc (TypeCheckType::visit): diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in index efa6309..835e113 100644 --- a/gcc/rust/Make-lang.in +++ b/gcc/rust/Make-lang.in @@ -92,9 +92,15 @@ GRS_OBJS = \ rust/rust-cfg-strip.o \ rust/rust-expand-visitor.o \ rust/rust-ast-builder.o \ + rust/rust-ast-builder-type.o \ rust/rust-derive.o \ rust/rust-derive-clone.o \ rust/rust-derive-copy.o \ + rust/rust-derive-debug.o \ + rust/rust-derive-default.o \ + rust/rust-derive-partial-eq.o \ + rust/rust-derive-eq.o \ + rust/rust-derive-hash.o \ rust/rust-proc-macro.o \ rust/rust-macro-invoc-lexer.o \ rust/rust-proc-macro-invoc-lexer.o \ @@ -109,6 +115,7 @@ GRS_OBJS = \ rust/rust-macro-builtins-format-args.o \ rust/rust-macro-builtins-location.o \ rust/rust-macro-builtins-include.o \ + rust/rust-token-tree-desugar.o \ rust/rust-fmt.o \ rust/rust-hir.o \ rust/rust-hir-map.o \ @@ -131,6 +138,8 @@ GRS_OBJS = \ rust/rust-default-resolver.o \ rust/rust-toplevel-name-resolver-2.0.o \ rust/rust-early-name-resolver-2.0.o \ + rust/rust-finalize-imports-2.0.o \ + rust/rust-ice-finalizer.o \ rust/rust-late-name-resolver-2.0.o \ rust/rust-immutable-name-resolution-context.o \ rust/rust-early-name-resolver.o \ @@ -144,6 +153,7 @@ GRS_OBJS = \ rust/rust-ast-resolve-path.o \ rust/rust-ast-resolve-stmt.o \ rust/rust-ast-resolve-struct-expr-field.o \ + rust/rust-forever-stack.o \ rust/rust-hir-type-check.o \ rust/rust-privacy-check.o \ rust/rust-privacy-ctx.o \ @@ -171,10 +181,18 @@ GRS_OBJS = \ rust/rust-borrow-checker.o \ rust/rust-borrow-checker-diagnostics.o\ rust/rust-bir-builder-expr-stmt.o \ + rust/rust-bir-builder-pattern.o \ rust/rust-bir-dump.o \ rust/rust-polonius.o\ rust/rust-hir-dot-operator.o \ rust/rust-hir-path-probe.o \ + rust/rust-hir-path.o \ + rust/rust-hir-type.o \ + rust/rust-hir-expr.o \ + rust/rust-hir-type-abstract.o \ + rust/rust-hir-item.o \ + rust/rust-hir-stmt.o \ + rust/rust-hir-generic-param.o \ rust/rust-type-util.o \ rust/rust-coercion.o \ rust/rust-casts.o \ @@ -188,6 +206,7 @@ GRS_OBJS = \ rust/rust-readonly-check.o \ rust/rust-hir-type-check-path.o \ rust/rust-unsafe-checker.o \ + rust/rust-hir-pattern-analysis.o \ rust/rust-compile-intrinsic.o \ rust/rust-compile-pattern.o \ rust/rust-compile-fnparam.o \ @@ -196,6 +215,7 @@ GRS_OBJS = \ rust/rust-compile-item.o \ rust/rust-compile-implitem.o \ rust/rust-compile-stmt.o \ + rust/rust-compile-asm.o \ rust/rust-compile-expr.o \ rust/rust-compile-type.o \ rust/rust-compile-block.o \ @@ -215,8 +235,13 @@ GRS_OBJS = \ rust/rust-dir-owner.o \ rust/rust-unicode.o \ rust/rust-punycode.o \ - rust/rust-lang-item.o \ + rust/rust-unwrap-segment.o \ + rust/rust-edition.o \ rust/rust-expand-format-args.o \ + rust/rust-lang-item.o \ + rust/rust-collect-lang-items.o \ + rust/rust-desugar-for-loops.o \ + rust/rust-desugar-question-mark.o \ $(END) # removed object files from here @@ -503,5 +528,5 @@ rust/%.o: rust/metadata/%.cc rust/libffi_polonius.a: \ rust/checks/errors/borrowck/ffi-polonius/Cargo.toml \ $(wildcard $(srcdir)/rust/checks/errors/borrowck/ffi-polonius/src/*) - cargo build --manifest-path $(srcdir)/rust/checks/errors/borrowck/ffi-polonius/Cargo.toml --release --target-dir rust/ffi-polonius + cd $(srcdir)/rust/checks/errors/borrowck/ffi-polonius/ && cargo build --offline --release --target-dir $(objdir)/rust/ffi-polonius cp rust/ffi-polonius/release/libffi_polonius.a rust/libffi_polonius.a diff --git a/gcc/rust/ast/rust-ast-builder-type.cc b/gcc/rust/ast/rust-ast-builder-type.cc new file mode 100644 index 0000000..13126b4 --- /dev/null +++ b/gcc/rust/ast/rust-ast-builder-type.cc @@ -0,0 +1,163 @@ +// Copyright (C) 2020-2024 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-ast-builder-type.h" +#include "rust-ast-builder.h" +#include "rust-ast-full.h" +#include "rust-common.h" + +namespace Rust { +namespace AST { + +ASTTypeBuilder::ASTTypeBuilder () : translated (nullptr) {} + +Type * +ASTTypeBuilder::build (Type &type) +{ + ASTTypeBuilder builder; + type.accept_vis (builder); + rust_assert (builder.translated != nullptr); + return builder.translated; +} + +void +ASTTypeBuilder::visit (BareFunctionType &fntype) +{ + /* TODO */ +} + +void +ASTTypeBuilder::visit (TupleType &tuple) +{ + std::vector<std::unique_ptr<Type> > elems; + for (auto &elem : tuple.get_elems ()) + { + Type *t = ASTTypeBuilder::build (*elem.get ()); + std::unique_ptr<Type> ty (t); + elems.push_back (std::move (ty)); + } + translated = new TupleType (std::move (elems), tuple.get_locus ()); +} + +void +ASTTypeBuilder::visit (TypePath &path) +{ + std::vector<std::unique_ptr<TypePathSegment> > segments; + for (auto &seg : path.get_segments ()) + { + switch (seg->get_type ()) + { + case TypePathSegment::REG: { + const TypePathSegment &segment + = (const TypePathSegment &) (*seg.get ()); + TypePathSegment *s + = new TypePathSegment (segment.get_ident_segment (), + segment.get_separating_scope_resolution (), + segment.get_locus ()); + std::unique_ptr<TypePathSegment> sg (s); + segments.push_back (std::move (sg)); + } + break; + + case TypePathSegment::GENERIC: { + TypePathSegmentGeneric &generic + = (TypePathSegmentGeneric &) (*seg.get ()); + + GenericArgs args + = Builder::new_generic_args (generic.get_generic_args ()); + TypePathSegmentGeneric *s + = new TypePathSegmentGeneric (generic.get_ident_segment (), false, + std::move (args), + generic.get_locus ()); + std::unique_ptr<TypePathSegment> sg (s); + segments.push_back (std::move (sg)); + } + break; + + case TypePathSegment::FUNCTION: { + rust_unreachable (); + // TODO + // const TypePathSegmentFunction &fn + // = (const TypePathSegmentFunction &) (*seg.get ()); + } + break; + } + } + + translated = new TypePath (std::move (segments), path.get_locus (), + path.has_opening_scope_resolution_op ()); +} + +void +ASTTypeBuilder::visit (QualifiedPathInType &path) +{ + /* TODO */ +} + +void +ASTTypeBuilder::visit (ArrayType &type) +{ + /* TODO */ +} + +void +ASTTypeBuilder::visit (ReferenceType &type) +{ + /* TODO */ +} + +void +ASTTypeBuilder::visit (RawPointerType &type) +{ + /* TODO */ +} + +void +ASTTypeBuilder::visit (SliceType &type) +{ + Type *t = ASTTypeBuilder::build (type.get_elem_type ()); + std::unique_ptr<Type> ty (t); + translated = new SliceType (std::move (ty), type.get_locus ()); +} + +void +ASTTypeBuilder::visit (InferredType &type) +{ + translated = new InferredType (type.get_locus ()); +} + +void +ASTTypeBuilder::visit (NeverType &type) +{ + translated = new NeverType (type.get_locus ()); +} + +void +ASTTypeBuilder::visit (TraitObjectTypeOneBound &type) +{ + /* TODO */ +} + +void +ASTTypeBuilder::visit (TraitObjectType &type) +{ + /* TODO */ +} + +} // namespace AST +} // namespace Rust diff --git a/gcc/rust/ast/rust-ast-builder-type.h b/gcc/rust/ast/rust-ast-builder-type.h new file mode 100644 index 0000000..b67ae3b --- /dev/null +++ b/gcc/rust/ast/rust-ast-builder-type.h @@ -0,0 +1,57 @@ +// Copyright (C) 2020-2024 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_AST_BUILDER_TYPE +#define RUST_AST_BUILDER_TYPE + +#include "rust-ast-visitor.h" + +namespace Rust { +namespace AST { + +class ASTTypeBuilder : public DefaultASTVisitor +{ +protected: + using DefaultASTVisitor::visit; + +public: + static Type *build (Type &type); + + void visit (BareFunctionType &fntype) override; + void visit (TupleType &tuple) override; + void visit (TypePath &path) override; + void visit (QualifiedPathInType &path) override; + void visit (ArrayType &type) override; + void visit (ReferenceType &type) override; + void visit (RawPointerType &type) override; + void visit (SliceType &type) override; + void visit (InferredType &type) override; + void visit (NeverType &type) override; + void visit (TraitObjectTypeOneBound &type) override; + void visit (TraitObjectType &type) override; + +private: + ASTTypeBuilder (); + + Type *translated; +}; + +} // namespace AST +} // namespace Rust + +#endif // RUST_AST_BUILDER_TYPE diff --git a/gcc/rust/ast/rust-ast-builder.cc b/gcc/rust/ast/rust-ast-builder.cc index 4679aa7..08c52b1 100644 --- a/gcc/rust/ast/rust-ast-builder.cc +++ b/gcc/rust/ast/rust-ast-builder.cc @@ -17,16 +17,31 @@ // <http://www.gnu.org/licenses/>. #include "rust-ast-builder.h" -#include "rust-ast-full-decls.h" -#include "rust-ast-full.h" +#include "optional.h" +#include "rust-ast-builder-type.h" +#include "rust-ast.h" #include "rust-common.h" #include "rust-expr.h" +#include "rust-keyword-values.h" +#include "rust-path.h" +#include "rust-item.h" +#include "rust-path.h" +#include "rust-pattern.h" +#include "rust-system.h" #include "rust-token.h" -#include "rust-make-unique.h" +#include <memory> namespace Rust { namespace AST { +std::unique_ptr<Stmt> +Builder::statementify (std::unique_ptr<Expr> &&value, + bool semicolon_followed) const +{ + return std::make_unique<ExprStmt> (std::move (value), loc, + semicolon_followed); +} + std::unique_ptr<Expr> Builder::literal_string (std::string &&content) const { @@ -36,6 +51,17 @@ Builder::literal_string (std::string &&content) const } std::unique_ptr<Expr> +Builder::literal_bool (bool b) const +{ + auto str + = b ? Values::Keywords::TRUE_LITERAL : Values::Keywords::FALSE_LITERAL; + + return std::unique_ptr<Expr> ( + new AST::LiteralExpr (std::move (str), Literal::LitType::BOOL, + PrimitiveCoreType::CORETYPE_BOOL, {}, loc)); +} + +std::unique_ptr<Expr> Builder::call (std::unique_ptr<Expr> &&path, std::vector<std::unique_ptr<Expr>> &&args) const { @@ -44,19 +70,56 @@ Builder::call (std::unique_ptr<Expr> &&path, } std::unique_ptr<Expr> +Builder::call (std::unique_ptr<Expr> &&path, std::unique_ptr<Expr> &&arg) const +{ + auto args = std::vector<std::unique_ptr<Expr>> (); + args.emplace_back (std::move (arg)); + + return call (std::move (path), std::move (args)); +} + +std::unique_ptr<Expr> Builder::array (std::vector<std::unique_ptr<Expr>> &&members) const { - auto elts = Rust::make_unique<ArrayElemsValues> (std::move (members), loc); + auto elts = std::make_unique<ArrayElemsValues> (std::move (members), loc); return std::unique_ptr<Expr> (new ArrayExpr (std::move (elts), {}, {}, loc)); } std::unique_ptr<Expr> +Builder::qualified_path_in_expression (std::unique_ptr<Type> &&type, + TypePath trait, + PathExprSegment segment) const +{ + auto segments = {segment}; + + return qualified_path_in_expression (std::move (type), trait, segments); +} + +std::unique_ptr<Expr> +Builder::qualified_path_in_expression ( + std::unique_ptr<Type> &&type, TypePath trait, + std::vector<PathExprSegment> &&segments) const +{ + auto qual_type = QualifiedPathType (std::move (type), loc, trait); + + return std::unique_ptr<QualifiedPathInExpression> ( + new QualifiedPathInExpression (qual_type, std::move (segments), {}, loc)); +} + +std::unique_ptr<Expr> Builder::identifier (std::string name) const { return std::unique_ptr<Expr> (new IdentifierExpr (name, {}, loc)); } +std::unique_ptr<Pattern> +Builder::identifier_pattern (std::string name, bool mut) const +{ + return std::unique_ptr<Pattern> ( + new IdentifierPattern (name, loc, false, mut)); +} + std::unique_ptr<Expr> Builder::tuple_idx (std::string receiver, int idx) const { @@ -64,12 +127,48 @@ Builder::tuple_idx (std::string receiver, int idx) const new TupleIndexExpr (identifier (receiver), idx, {}, loc)); } +std::unique_ptr<Expr> +Builder::tuple (std::vector<std::unique_ptr<Expr>> &&values) const +{ + return std::unique_ptr<TupleExpr> ( + new TupleExpr (std::move (values), {}, {}, loc)); +} + +std::unique_ptr<Param> +Builder::self_ref_param (bool mutability) const +{ + return std::make_unique<SelfParam> (tl::nullopt, mutability, loc); +} + +std::unique_ptr<Param> +Builder::function_param (std::unique_ptr<Pattern> &&pattern, + std::unique_ptr<Type> &&type) const +{ + return std::unique_ptr<FunctionParam> ( + new FunctionParam (std::move (pattern), std::move (type), {}, loc)); +} + FunctionQualifiers Builder::fn_qualifiers () const { return FunctionQualifiers (loc, Async::No, Const::No, Unsafety::Normal); } +std::unique_ptr<Function> +Builder::function (std::string function_name, + std::vector<std::unique_ptr<Param>> params, + std::unique_ptr<Type> return_type, + std::unique_ptr<BlockExpr> block, + std::vector<std::unique_ptr<GenericParam>> generic_params, + FunctionQualifiers qualifiers, WhereClause where_clause, + Visibility visibility) const +{ + return std::unique_ptr<Function> ( + new Function (function_name, qualifiers, std::move (generic_params), + std::move (params), std::move (return_type), where_clause, + std::move (block), visibility, {}, loc)); +} + PathExprSegment Builder::path_segment (std::string seg) const { @@ -83,6 +182,28 @@ Builder::type_path_segment (std::string seg) const new TypePathSegment (seg, false, loc)); } +std::unique_ptr<TypePathSegment> +Builder::type_path_segment (LangItem::Kind lang_item) const +{ + return std::unique_ptr<TypePathSegment> ( + new TypePathSegment (lang_item, loc)); +} + +std::unique_ptr<TypePathSegment> +Builder::type_path_segment_generic (std::string seg, GenericArgs args) const +{ + return std::unique_ptr<TypePathSegment> ( + new TypePathSegmentGeneric (PathIdentSegment (seg, loc), false, args, loc)); +} + +std::unique_ptr<TypePathSegment> +Builder::type_path_segment_generic (LangItem::Kind lang_item, + GenericArgs args) const +{ + return std::unique_ptr<TypePathSegment> ( + new TypePathSegmentGeneric (lang_item, args, loc)); +} + std::unique_ptr<Type> Builder::single_type_path (std::string type) const { @@ -92,32 +213,147 @@ Builder::single_type_path (std::string type) const return std::unique_ptr<Type> (new TypePath (std::move (segments), loc)); } +std::unique_ptr<Type> +Builder::single_type_path (LangItem::Kind lang_item) const +{ + return std::unique_ptr<Type> (new TypePath (lang_item, {}, loc)); +} + +std::unique_ptr<Type> +Builder::single_generic_type_path (std::string type, GenericArgs args) const +{ + auto segments = std::vector<std::unique_ptr<TypePathSegment>> (); + segments.emplace_back (type_path_segment_generic (type, args)); + + return std::unique_ptr<Type> (new TypePath (std::move (segments), loc)); +} + +std::unique_ptr<Type> +Builder::single_generic_type_path (LangItem::Kind lang_item, + GenericArgs args) const +{ + auto segments = std::vector<std::unique_ptr<TypePathSegment>> (); + segments.emplace_back (type_path_segment_generic (lang_item, args)); + + return std::unique_ptr<Type> (new TypePath (std::move (segments), loc)); +} + +TypePath +Builder::type_path (std::vector<std::unique_ptr<TypePathSegment>> &&segments, + bool opening_scope) const +{ + return TypePath (std::move (segments), loc, opening_scope); +} + +TypePath +Builder::type_path (std::vector<std::string> &&segments, + bool opening_scope) const +{ + auto type_segments = std::vector<std::unique_ptr<TypePathSegment>> (); + + for (auto &&segment : segments) + type_segments.emplace_back (type_path_segment (segment)); + + return TypePath (std::move (type_segments), loc, opening_scope); +} + +TypePath +Builder::type_path (std::unique_ptr<TypePathSegment> &&segment) const +{ + auto segments = std::vector<std::unique_ptr<TypePathSegment>> (); + segments.emplace_back (std::move (segment)); + + return type_path (std::move (segments)); +} + +TypePath +Builder::type_path (std::string type) const +{ + return type_path (type_path_segment (type)); +} + +TypePath +Builder::type_path (LangItem::Kind lang_item) const +{ + return type_path (type_path_segment (lang_item)); +} + +std::unique_ptr<Type> +Builder::reference_type (std::unique_ptr<TypeNoBounds> &&inner_type, + bool mutability) const +{ + return std::make_unique<ReferenceType> (mutability, std::move (inner_type), + loc); +} + PathInExpression -Builder::path_in_expression (std::vector<std::string> &&segments) const +Builder::path_in_expression (std::vector<std::string> &&segments, + bool opening_scope) const { auto path_segments = std::vector<PathExprSegment> (); for (auto &seg : segments) path_segments.emplace_back (path_segment (seg)); - return PathInExpression (std::move (path_segments), {}, loc); + return PathInExpression (std::move (path_segments), {}, loc, opening_scope); } -std::unique_ptr<Expr> +PathInExpression +Builder::path_in_expression (LangItem::Kind lang_item) const +{ + return PathInExpression (lang_item, {}, loc); +} + +PathInExpression +Builder::variant_path (const std::string &enum_path, + const std::string &variant) const +{ + return PathInExpression ({path_segment (enum_path), path_segment (variant)}, + {}, loc, false); +} + +std::unique_ptr<BlockExpr> +Builder::block (tl::optional<std::unique_ptr<Stmt>> &&stmt, + std::unique_ptr<Expr> &&tail_expr) const +{ + auto stmts = std::vector<std::unique_ptr<Stmt>> (); + + if (stmt) + stmts.emplace_back (std::move (*stmt)); + + return block (std::move (stmts), std::move (tail_expr)); +} + +std::unique_ptr<BlockExpr> +Builder::block () const +{ + auto stmts = std::vector<std::unique_ptr<Stmt>> (); + + return block (std::move (stmts)); +} + +std::unique_ptr<BlockExpr> Builder::block (std::vector<std::unique_ptr<Stmt>> &&stmts, std::unique_ptr<Expr> &&tail_expr) const { - return std::unique_ptr<Expr> (new BlockExpr (std::move (stmts), - std::move (tail_expr), {}, {}, - LoopLabel::error (), loc, loc)); + return std::unique_ptr<BlockExpr> (new BlockExpr (std::move (stmts), + std::move (tail_expr), {}, + {}, tl::nullopt, loc, loc)); +} + +std::unique_ptr<Expr> +Builder::return_expr (std::unique_ptr<Expr> &&to_return) +{ + return std::unique_ptr<Expr> ( + new ReturnExpr (std::move (to_return), {}, loc)); } std::unique_ptr<Stmt> -Builder::let (std::unique_ptr<Pattern> pattern, std::unique_ptr<Type> type, - std::unique_ptr<Expr> init) const +Builder::let (std::unique_ptr<Pattern> &&pattern, std::unique_ptr<Type> &&type, + std::unique_ptr<Expr> &&init) const { return std::unique_ptr<Stmt> (new LetStmt (std::move (pattern), std::move (init), std::move (type), - {}, loc)); + tl::nullopt, {}, loc)); } std::unique_ptr<Expr> @@ -136,6 +372,37 @@ Builder::deref (std::unique_ptr<Expr> &&of) const } std::unique_ptr<Expr> +Builder::comparison_expr (std::unique_ptr<Expr> &&lhs, + std::unique_ptr<Expr> &&rhs, + ComparisonOperator op) const +{ + return std::make_unique<ComparisonExpr> (std::move (lhs), std::move (rhs), op, + loc); +} + +std::unique_ptr<Expr> +Builder::boolean_operation (std::unique_ptr<Expr> &&lhs, + std::unique_ptr<Expr> &&rhs, + LazyBooleanOperator op) const +{ + return std::make_unique<LazyBooleanExpr> (std::move (lhs), std::move (rhs), + op, loc); +} + +std::unique_ptr<Stmt> +Builder::struct_struct (std::string struct_name, + std::vector<std::unique_ptr<GenericParam>> &&generics, + std::vector<StructField> &&fields) +{ + auto is_unit = fields.empty (); + + return std::unique_ptr<Stmt> ( + new StructStruct (std::move (fields), struct_name, std::move (generics), + WhereClause::create_empty (), is_unit, + Visibility::create_private (), {}, loc)); +} + +std::unique_ptr<Expr> Builder::struct_expr_struct (std::string struct_name) const { return std::unique_ptr<Expr> ( @@ -147,9 +414,16 @@ Builder::struct_expr ( std::string struct_name, std::vector<std::unique_ptr<StructExprField>> &&fields) const { + return struct_expr (path_in_expression ({struct_name}), std::move (fields)); +} + +std::unique_ptr<Expr> +Builder::struct_expr ( + PathInExpression struct_name, + std::vector<std::unique_ptr<StructExprField>> &&fields) const +{ return std::unique_ptr<Expr> ( - new StructExprStructFields (path_in_expression ({struct_name}), - std::move (fields), loc)); + new StructExprStructFields (struct_name, std::move (fields), loc)); } std::unique_ptr<StructExprField> @@ -174,5 +448,266 @@ Builder::wildcard () const return std::unique_ptr<Pattern> (new WildcardPattern (loc)); } +std::unique_ptr<Pattern> +Builder::ref_pattern (std::unique_ptr<Pattern> &&inner) const +{ + return std::make_unique<ReferencePattern> (std::move (inner), false, false, + loc); +} + +std::unique_ptr<Path> +Builder::lang_item_path (LangItem::Kind kind) const +{ + return std::unique_ptr<Path> (new PathInExpression (kind, {}, loc)); +} + +std::unique_ptr<Expr> +Builder::match (std::unique_ptr<Expr> &&scrutinee, + std::vector<MatchCase> &&cases) +{ + return std::unique_ptr<Expr> ( + new MatchExpr (std::move (scrutinee), std::move (cases), {}, {}, loc)); +} + +MatchArm +Builder::match_arm (std::unique_ptr<Pattern> &&pattern) +{ + auto patterns = std::vector<std::unique_ptr<Pattern>> (); + patterns.emplace_back (std::move (pattern)); + + return MatchArm (std::move (patterns), loc); +} + +MatchCase +Builder::match_case (std::unique_ptr<Pattern> &&pattern, + std::unique_ptr<Expr> &&expr) +{ + return MatchCase (match_arm (std::move (pattern)), std::move (expr)); +} + +std::unique_ptr<Expr> +Builder::loop (std::vector<std::unique_ptr<Stmt>> &&stmts) +{ + auto block_expr = block (std::move (stmts), nullptr); + + return std::unique_ptr<Expr> (new LoopExpr (std::move (block_expr), loc)); +} + +std::unique_ptr<TypeParamBound> +Builder::trait_bound (TypePath bound) +{ + return std::make_unique<TraitBound> (bound, loc); +} + +std::unique_ptr<Item> +Builder::trait_impl (TypePath trait_path, std::unique_ptr<Type> target, + std::vector<std::unique_ptr<AssociatedItem>> trait_items, + std::vector<std::unique_ptr<GenericParam>> generics, + WhereClause where_clause, Visibility visibility) const +{ + return std::unique_ptr<Item> ( + new TraitImpl (trait_path, /* unsafe */ false, + /* exclam */ false, std::move (trait_items), + std::move (generics), std::move (target), where_clause, + visibility, {}, {}, loc)); +} + +std::unique_ptr<GenericParam> +Builder::generic_type_param ( + std::string type_representation, + std::vector<std::unique_ptr<TypeParamBound>> &&bounds, + std::unique_ptr<Type> &&type) +{ + return std::make_unique<TypeParam> (type_representation, loc, + std::move (bounds), std::move (type), + std::vector<Attribute> ()); +} + +std::unique_ptr<Type> +Builder::new_type (Type &type) +{ + Type *t = ASTTypeBuilder::build (type); + return std::unique_ptr<Type> (t); +} + +std::unique_ptr<GenericParam> +Builder::new_lifetime_param (LifetimeParam ¶m) +{ + Lifetime l = new_lifetime (param.get_lifetime ()); + std::vector<Lifetime> lifetime_bounds; + for (auto b : param.get_lifetime_bounds ()) + { + Lifetime bl = new_lifetime (b); + lifetime_bounds.push_back (bl); + } + + auto p = new LifetimeParam (l, std::move (lifetime_bounds), + param.get_outer_attrs (), param.get_locus ()); + return std::unique_ptr<GenericParam> (p); +} + +std::unique_ptr<GenericParam> +Builder::new_type_param ( + TypeParam ¶m, std::vector<std::unique_ptr<TypeParamBound>> extra_bounds) +{ + location_t locus = param.get_locus (); + AST::AttrVec outer_attrs = param.get_outer_attrs (); + Identifier type_representation = param.get_type_representation (); + std::vector<std::unique_ptr<TypeParamBound>> type_param_bounds; + std::unique_ptr<Type> type = nullptr; + + if (param.has_type ()) + type = new_type (param.get_type ()); + + for (auto &&extra_bound : extra_bounds) + type_param_bounds.emplace_back (std::move (extra_bound)); + + for (const auto &b : param.get_type_param_bounds ()) + { + switch (b->get_bound_type ()) + { + case TypeParamBound::TypeParamBoundType::TRAIT: { + const TraitBound &tb = (const TraitBound &) *b.get (); + const TypePath &path = tb.get_type_path (); + + std::vector<LifetimeParam> for_lifetimes; + for (const auto &lifetime : tb.get_for_lifetimes ()) + { + std::vector<Lifetime> lifetime_bounds; + for (const auto &b : lifetime.get_lifetime_bounds ()) + { + Lifetime bl = new_lifetime (b); + lifetime_bounds.push_back (std::move (bl)); + } + + Lifetime nl = new_lifetime (lifetime.get_lifetime ()); + LifetimeParam p (std::move (nl), std::move (lifetime_bounds), + {}, lifetime.get_locus ()); + for_lifetimes.push_back (std::move (p)); + } + + std::vector<std::unique_ptr<TypePathSegment>> segments; + for (auto &seg : path.get_segments ()) + { + switch (seg->get_type ()) + { + case TypePathSegment::REG: { + const TypePathSegment &segment + = (const TypePathSegment &) (*seg.get ()); + TypePathSegment *s = new TypePathSegment ( + segment.get_ident_segment (), + segment.get_separating_scope_resolution (), + segment.get_locus ()); + std::unique_ptr<TypePathSegment> sg (s); + segments.push_back (std::move (sg)); + } + break; + + case TypePathSegment::GENERIC: { + TypePathSegmentGeneric &generic + = (TypePathSegmentGeneric &) (*seg.get ()); + + GenericArgs args + = new_generic_args (generic.get_generic_args ()); + TypePathSegmentGeneric *s = new TypePathSegmentGeneric ( + generic.get_ident_segment (), false, std::move (args), + generic.get_locus ()); + std::unique_ptr<TypePathSegment> sg (s); + segments.push_back (std::move (sg)); + } + break; + + case TypePathSegment::FUNCTION: { + rust_unreachable (); + // TODO + // const TypePathSegmentFunction &fn + // = (const TypePathSegmentFunction &) (*seg.get ()); + } + break; + } + } + + TypePath p (std::move (segments), path.get_locus (), + path.has_opening_scope_resolution_op ()); + + TraitBound *b = new TraitBound (std::move (p), tb.get_locus (), + tb.is_in_parens (), + tb.has_opening_question_mark (), + std::move (for_lifetimes)); + std::unique_ptr<TypeParamBound> bound (b); + type_param_bounds.push_back (std::move (bound)); + } + break; + + case TypeParamBound::TypeParamBoundType::LIFETIME: { + const Lifetime &l = (const Lifetime &) *b.get (); + + auto bl = new Lifetime (l.get_lifetime_type (), + l.get_lifetime_name (), l.get_locus ()); + std::unique_ptr<TypeParamBound> bound (bl); + type_param_bounds.push_back (std::move (bound)); + } + break; + } + } + + auto type_param + = new TypeParam (type_representation, locus, std::move (type_param_bounds), + std::move (type), std::move (outer_attrs)); + + return std::unique_ptr<GenericParam> (type_param); +} + +Lifetime +Builder::new_lifetime (const Lifetime &lifetime) +{ + return Lifetime (lifetime.get_lifetime_type (), lifetime.get_lifetime_name (), + lifetime.get_locus ()); +} + +GenericArgs +Builder::new_generic_args (GenericArgs &args) +{ + std::vector<Lifetime> lifetime_args; + std::vector<GenericArg> generic_args; + std::vector<GenericArgsBinding> binding_args; + location_t locus = args.get_locus (); + + for (const auto &lifetime : args.get_lifetime_args ()) + { + Lifetime l = new_lifetime (lifetime); + lifetime_args.push_back (std::move (l)); + } + + for (auto &binding : args.get_binding_args ()) + { + Type &t = *binding.get_type_ptr ().get (); + std::unique_ptr<Type> ty = new_type (t); + GenericArgsBinding b (binding.get_identifier (), std::move (ty), + binding.get_locus ()); + binding_args.push_back (std::move (b)); + } + + for (auto &arg : args.get_generic_args ()) + { + switch (arg.get_kind ()) + { + case GenericArg::Kind::Type: { + std::unique_ptr<Type> ty = new_type (arg.get_type ()); + GenericArg arg = GenericArg::create_type (std::move (ty)); + } + break; + + default: + // FIXME + rust_unreachable (); + break; + } + } + + return GenericArgs (std::move (lifetime_args), std::move (generic_args), + std::move (binding_args), locus); +} + } // namespace AST } // namespace Rust diff --git a/gcc/rust/ast/rust-ast-builder.h b/gcc/rust/ast/rust-ast-builder.h index aed71e7..41ce118 100644 --- a/gcc/rust/ast/rust-ast-builder.h +++ b/gcc/rust/ast/rust-ast-builder.h @@ -20,10 +20,45 @@ #define AST_BUILDER_H #include "rust-ast-full.h" +#include "rust-expr.h" +#include "rust-ast.h" +#include "rust-item.h" +#include "rust-operators.h" namespace Rust { namespace AST { +template <typename T> +std::vector<std::unique_ptr<T>> +vec (std::unique_ptr<T> &&t) +{ + auto v = std::vector<std::unique_ptr<T>> (); + + v.emplace_back (std::move (t)); + + return v; +} + +template <typename T> +std::vector<std::unique_ptr<T>> +vec (std::unique_ptr<T> &&t1, std::unique_ptr<T> &&t2) +{ + auto v = std::vector<std::unique_ptr<T>> (); + + v.emplace_back (std::move (t1)); + v.emplace_back (std::move (t2)); + + return v; +} + +/* Pointer-ify something */ +template <typename T> +static std::unique_ptr<T> +ptrify (T value) +{ + return std::unique_ptr<T> (new T (value)); +} + // TODO: Use this builder when expanding regular macros /* Builder class with helper methods to create AST nodes. This builder is * tailored towards generating multiple AST nodes from a single location, and @@ -33,15 +68,28 @@ class Builder public: Builder (location_t loc) : loc (loc) {} + /* Create an expression statement from an expression */ + std::unique_ptr<Stmt> statementify (std::unique_ptr<Expr> &&value, + bool semicolon_followed = true) const; + /* Create a string literal expression ("content") */ std::unique_ptr<Expr> literal_string (std::string &&content) const; + /* Create a boolean literal expression (true) */ + std::unique_ptr<Expr> literal_bool (bool b) const; + /* Create an identifier expression (`variable`) */ std::unique_ptr<Expr> identifier (std::string name) const; + std::unique_ptr<Pattern> identifier_pattern (std::string name, + bool mut = false) const; /* Create a tuple index expression (`receiver.0`) */ std::unique_ptr<Expr> tuple_idx (std::string receiver, int idx) const; + /* Create a tuple expression (`(a1, a2, a3)`) */ + std::unique_ptr<Expr> tuple (std::vector<std::unique_ptr<Expr>> &&values + = {}) const; + /* Create a reference to an expression (`&of`) */ std::unique_ptr<Expr> ref (std::unique_ptr<Expr> &&of, bool mut = false) const; @@ -49,23 +97,45 @@ public: /* Create a dereference of an expression (`*of`) */ std::unique_ptr<Expr> deref (std::unique_ptr<Expr> &&of) const; + /* Build a comparison expression (`lhs == rhs`) */ + std::unique_ptr<Expr> comparison_expr (std::unique_ptr<Expr> &&lhs, + std::unique_ptr<Expr> &&rhs, + ComparisonOperator op) const; + + /* Build a lazy boolean operator expression (`lhs && rhs`) */ + std::unique_ptr<Expr> boolean_operation (std::unique_ptr<Expr> &&lhs, + std::unique_ptr<Expr> &&rhs, + LazyBooleanOperator op) const; + /* Create a block with an optional tail expression */ - std::unique_ptr<Expr> block (std::vector<std::unique_ptr<Stmt>> &&stmts, - std::unique_ptr<Expr> &&tail_expr - = nullptr) const; + std::unique_ptr<BlockExpr> block (std::vector<std::unique_ptr<Stmt>> &&stmts, + std::unique_ptr<Expr> &&tail_expr + = nullptr) const; + std::unique_ptr<BlockExpr> block (tl::optional<std::unique_ptr<Stmt>> &&stmt, + std::unique_ptr<Expr> &&tail_expr + = nullptr) const; + /* Create an empty block */ + std::unique_ptr<BlockExpr> block () const; + + /* Create an early return expression with an optional expression */ + std::unique_ptr<Expr> return_expr (std::unique_ptr<Expr> &&to_return + = nullptr); /* Create a let binding with an optional type and initializer (`let <name> : * <type> = <init>`) */ - std::unique_ptr<Stmt> let (std::unique_ptr<Pattern> pattern, - std::unique_ptr<Type> type = nullptr, - std::unique_ptr<Expr> init = nullptr) const; + std::unique_ptr<Stmt> let (std::unique_ptr<Pattern> &&pattern, + std::unique_ptr<Type> &&type = nullptr, + std::unique_ptr<Expr> &&init = nullptr) const; /** * Create a call expression to a function, struct or enum variant, given its * arguments (`path(arg0, arg1, arg2)`) */ std::unique_ptr<Expr> call (std::unique_ptr<Expr> &&path, - std::vector<std::unique_ptr<Expr>> &&args) const; + std::vector<std::unique_ptr<Expr>> &&args + = {}) const; + std::unique_ptr<Expr> call (std::unique_ptr<Expr> &&path, + std::unique_ptr<Expr> &&arg) const; /** * Create an array expression (`[member0, member1, member2]`) @@ -73,36 +143,107 @@ public: std::unique_ptr<Expr> array (std::vector<std::unique_ptr<Expr>> &&members) const; + /* Create a qualified path in expression (`<type as Trait>::seg::expr`) */ + std::unique_ptr<Expr> + qualified_path_in_expression (std::unique_ptr<Type> &&type, TypePath trait, + PathExprSegment segment) const; + std::unique_ptr<Expr> + qualified_path_in_expression (std::unique_ptr<Type> &&type, TypePath trait, + std::vector<PathExprSegment> &&segments + = {}) const; + + /* Self parameter for a function definition (`&self`) */ + std::unique_ptr<Param> self_ref_param (bool mutability = false) const; + /* A regular named function parameter for a definition (`a: type`) */ + std::unique_ptr<Param> function_param (std::unique_ptr<Pattern> &&pattern, + std::unique_ptr<Type> &&type) const; + /* Empty function qualifiers, with no specific qualifiers */ FunctionQualifiers fn_qualifiers () const; + std::unique_ptr<Function> + function (std::string function_name, + std::vector<std::unique_ptr<Param>> params, + std::unique_ptr<Type> return_type, std::unique_ptr<BlockExpr> block, + std::vector<std::unique_ptr<GenericParam>> generic_params = {}, + FunctionQualifiers qualifiers + = FunctionQualifiers (UNKNOWN_LOCATION, Async::No, Const::No, + Unsafety::Normal), + WhereClause where_clause = WhereClause::create_empty (), + Visibility visibility = Visibility::create_private ()) const; + /* Create a single path segment from one string */ PathExprSegment path_segment (std::string seg) const; /* And similarly for type path segments */ std::unique_ptr<TypePathSegment> type_path_segment (std::string seg) const; + std::unique_ptr<TypePathSegment> + type_path_segment (LangItem::Kind lang_item) const; + + std::unique_ptr<TypePathSegment> + type_path_segment_generic (std::string seg, GenericArgs args) const; + std::unique_ptr<TypePathSegment> + type_path_segment_generic (LangItem::Kind lang_item, GenericArgs args) const; /* Create a Type from a single string - the most basic kind of type in our AST */ std::unique_ptr<Type> single_type_path (std::string type) const; + std::unique_ptr<Type> single_type_path (LangItem::Kind lang_item) const; + + std::unique_ptr<Type> single_generic_type_path (std::string type, + GenericArgs args) const; + std::unique_ptr<Type> single_generic_type_path (LangItem::Kind lang_item, + GenericArgs args) const; + + TypePath type_path (std::vector<std::unique_ptr<TypePathSegment>> &&segment, + bool opening_scope = false) const; + TypePath type_path (std::vector<std::string> &&segments, + bool opening_scope = false) const; + TypePath type_path (std::unique_ptr<TypePathSegment> &&segment) const; + TypePath type_path (std::string type) const; + TypePath type_path (LangItem::Kind lang_item) const; + + std::unique_ptr<Type> + reference_type (std::unique_ptr<TypeNoBounds> &&inner_type, + bool mutability = false) const; /** * Create a path in expression from multiple segments (`Clone::clone`). You * do not need to separate the segments using `::`, you can simply provide a * vector of strings to the functions which will get turned into path segments */ - PathInExpression - path_in_expression (std::vector<std::string> &&segments) const; + PathInExpression path_in_expression (std::vector<std::string> &&segments, + bool opening_scope = false) const; + + /** + * Create a path in expression from a lang item. + */ + PathInExpression path_in_expression (LangItem::Kind lang_item) const; + + /* Create the path to an enum's variant (`Result::Ok`) */ + PathInExpression variant_path (const std::string &enum_path, + const std::string &variant) const; + + /* Create a new struct */ + std::unique_ptr<Stmt> + struct_struct (std::string struct_name, + std::vector<std::unique_ptr<GenericParam>> &&generics, + std::vector<StructField> &&fields); /* Create a struct expression for unit structs (`S`) */ std::unique_ptr<Expr> struct_expr_struct (std::string struct_name) const; /** * Create an expression for struct instantiation with fields (`S { a, b: c }`) + * Named tuple expressions (`S(a, b, c)`) are call expressions and can thus be + * constructed with `call` */ std::unique_ptr<Expr> struct_expr (std::string struct_name, std::vector<std::unique_ptr<StructExprField>> &&fields) const; + std::unique_ptr<Expr> + struct_expr (PathInExpression struct_name, + std::vector<std::unique_ptr<StructExprField>> &&fields) const; /* Create a field expression for struct instantiation (`field_name: value`) */ std::unique_ptr<StructExprField> @@ -115,6 +256,47 @@ public: /* Create a wildcard pattern (`_`) */ std::unique_ptr<Pattern> wildcard () const; + /* Create a reference pattern (`&pattern`) */ + std::unique_ptr<Pattern> ref_pattern (std::unique_ptr<Pattern> &&inner) const; + + /* Create a lang item path usable as a general path */ + std::unique_ptr<Path> lang_item_path (LangItem::Kind) const; + + /* Create match expressions and their components */ + std::unique_ptr<Expr> match (std::unique_ptr<Expr> &&scrutinee, + std::vector<MatchCase> &&cases); + MatchArm match_arm (std::unique_ptr<Pattern> &&pattern); + MatchCase match_case (std::unique_ptr<Pattern> &&pattern, + std::unique_ptr<Expr> &&expr); + + /* Create a loop expression */ + std::unique_ptr<Expr> loop (std::vector<std::unique_ptr<Stmt>> &&stmts); + + std::unique_ptr<TypeParamBound> trait_bound (TypePath bound); + std::unique_ptr<Item> + trait_impl (TypePath trait_path, std::unique_ptr<Type> target, + std::vector<std::unique_ptr<AssociatedItem>> trait_items = {}, + std::vector<std::unique_ptr<GenericParam>> generics = {}, + WhereClause where_clause = WhereClause::create_empty (), + Visibility visibility = Visibility::create_private ()) const; + + std::unique_ptr<GenericParam> + generic_type_param (std::string type_representation, + std::vector<std::unique_ptr<TypeParamBound>> &&bounds, + std::unique_ptr<Type> &&type = nullptr); + + static std::unique_ptr<Type> new_type (Type &type); + + static std::unique_ptr<GenericParam> + new_lifetime_param (LifetimeParam ¶m); + + static std::unique_ptr<GenericParam> new_type_param ( + TypeParam ¶m, + std::vector<std::unique_ptr<TypeParamBound>> extra_trait_bounds = {}); + + static Lifetime new_lifetime (const Lifetime &lifetime); + + static GenericArgs new_generic_args (GenericArgs &args); private: /** diff --git a/gcc/rust/ast/rust-ast-collector.cc b/gcc/rust/ast/rust-ast-collector.cc index 6980fef..c850e96 100644 --- a/gcc/rust/ast/rust-ast-collector.cc +++ b/gcc/rust/ast/rust-ast-collector.cc @@ -15,12 +15,16 @@ // 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-ast-collector.h" #include "rust-ast.h" #include "rust-diagnostics.h" #include "rust-expr.h" #include "rust-item.h" #include "rust-keyword-values.h" +#include "rust-location.h" +#include "rust-path.h" +#include "rust-system.h" #include "rust-token.h" namespace Rust { @@ -250,29 +254,6 @@ TokenCollector::visit (Visibility &vis) } void -TokenCollector::visit (NamedFunctionParam ¶m) -{ - auto name = param.get_name (); - if (!param.is_variadic ()) - { - push ( - Rust::Token::make_identifier (param.get_locus (), std::move (name))); - push (Rust::Token::make (COLON, UNDEF_LOCATION)); - visit (param.get_type ()); - } - else - { - if (name != "") - { - push (Rust::Token::make_identifier (param.get_locus (), - std::move (name))); - push (Rust::Token::make (COLON, UNDEF_LOCATION)); - } - push (Rust::Token::make (ELLIPSIS, UNDEF_LOCATION)); - } -} - -void TokenCollector::visit (std::vector<std::unique_ptr<GenericParam>> ¶ms) { push (Rust::Token::make (LEFT_ANGLE, UNDEF_LOCATION)); @@ -510,7 +491,7 @@ TokenCollector::visit (ConstGenericParam ¶m) if (param.has_default_value ()) { push (Rust::Token::make (EQUAL, UNDEF_LOCATION)); - visit (param.get_default_value ()); + visit (param.get_default_value_unchecked ()); } } @@ -552,11 +533,23 @@ TokenCollector::visit (PathExprSegment &segment) void TokenCollector::visit (PathInExpression &path) { - if (path.opening_scope_resolution ()) + if (path.is_lang_item ()) { - push (Rust::Token::make (SCOPE_RESOLUTION, path.get_locus ())); + push (Rust::Token::make (TokenId::HASH, path.get_locus ())); + push (Rust::Token::make (TokenId::LEFT_SQUARE, path.get_locus ())); + push (Rust::Token::make_identifier (path.get_locus (), "lang")); + push (Rust::Token::make (TokenId::EQUAL, path.get_locus ())); + push ( + Rust::Token::make_string (path.get_locus (), + LangItem::ToString (path.get_lang_item ()))); + push (Rust::Token::make (TokenId::RIGHT_SQUARE, path.get_locus ())); + + return; } + if (path.opening_scope_resolution ()) + push (Rust::Token::make (SCOPE_RESOLUTION, path.get_locus ())); + visit_items_joined_by_separator (path.get_segments (), SCOPE_RESOLUTION); } @@ -565,10 +558,14 @@ TokenCollector::visit (TypePathSegment &segment) { // Syntax: // PathIdentSegment - auto ident_segment = segment.get_ident_segment (); - auto id = ident_segment.as_string (); - push ( - Rust::Token::make_identifier (ident_segment.get_locus (), std::move (id))); + + auto locus = segment.is_lang_item () + ? segment.get_locus () + : segment.get_ident_segment ().get_locus (); + auto segment_string = segment.is_lang_item () + ? LangItem::PrettyString (segment.get_lang_item ()) + : segment.get_ident_segment ().as_string (); + push (Rust::Token::make_identifier (locus, std::move (segment_string))); } void @@ -580,10 +577,13 @@ TokenCollector::visit (TypePathSegmentGeneric &segment) // `<` `>` // | `<` ( GenericArg `,` )* GenericArg `,`? `>` - auto ident_segment = segment.get_ident_segment (); - auto id = ident_segment.as_string (); - push ( - Rust::Token::make_identifier (ident_segment.get_locus (), std::move (id))); + auto locus = segment.is_lang_item () + ? segment.get_locus () + : segment.get_ident_segment ().get_locus (); + auto segment_string = segment.is_lang_item () + ? LangItem::PrettyString (segment.get_lang_item ()) + : segment.get_ident_segment ().as_string (); + push (Rust::Token::make_identifier (locus, std::move (segment_string))); if (segment.get_separating_scope_resolution ()) push (Rust::Token::make (SCOPE_RESOLUTION, UNDEF_LOCATION)); @@ -639,8 +639,6 @@ TokenCollector::visit (GenericArg &arg) push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (path))); } break; - case GenericArg::Kind::Error: - rust_unreachable (); } } @@ -697,19 +695,19 @@ TokenCollector::visit (TypePath &path) void TokenCollector::visit (PathIdentSegment &segment) { - if (segment.is_super_segment ()) + if (segment.is_super_path_seg ()) { push (Rust::Token::make (SUPER, segment.get_locus ())); } - else if (segment.is_crate_segment ()) + else if (segment.is_crate_path_seg ()) { push (Rust::Token::make (CRATE, segment.get_locus ())); } - else if (segment.is_lower_self ()) + else if (segment.is_lower_self_seg ()) { push (Rust::Token::make (SELF, segment.get_locus ())); } - else if (segment.is_big_self ()) + else if (segment.is_big_self_seg ()) { push (Rust::Token::make (SELF_ALIAS, segment.get_locus ())); } @@ -1279,7 +1277,7 @@ TokenCollector::visit (ContinueExpr &expr) { push (Rust::Token::make (CONTINUE, expr.get_locus ())); if (expr.has_label ()) - visit (expr.get_label ()); + visit (expr.get_label_unchecked ()); } void @@ -1287,7 +1285,7 @@ TokenCollector::visit (BreakExpr &expr) { push (Rust::Token::make (BREAK, expr.get_locus ())); if (expr.has_label ()) - visit (expr.get_label ()); + visit (expr.get_label_unchecked ()); if (expr.has_break_expr ()) visit (expr.get_break_expr ()); } @@ -1522,6 +1520,47 @@ void TokenCollector::visit (InlineAsm &expr) {} +void +TokenCollector::visit (LlvmInlineAsm &expr) +{ + push (Rust::Token::make_identifier (expr.get_locus (), "llvm_asm")); + push (Rust::Token::make (EXCLAM, expr.get_locus ())); + push (Rust::Token::make (LEFT_PAREN, expr.get_locus ())); + for (auto &template_str : expr.get_templates ()) + push (Rust::Token::make_string (template_str.get_locus (), + std::move (template_str.symbol))); + + push (Rust::Token::make (COLON, expr.get_locus ())); + for (auto output : expr.get_outputs ()) + { + push (Rust::Token::make_string (expr.get_locus (), + std::move (output.constraint))); + visit (output.expr); + push (Rust::Token::make (COMMA, expr.get_locus ())); + } + + push (Rust::Token::make (COLON, expr.get_locus ())); + for (auto input : expr.get_inputs ()) + { + push (Rust::Token::make_string (expr.get_locus (), + std::move (input.constraint))); + visit (input.expr); + push (Rust::Token::make (COMMA, expr.get_locus ())); + } + + push (Rust::Token::make (COLON, expr.get_locus ())); + for (auto &clobber : expr.get_clobbers ()) + { + push (Rust::Token::make_string (expr.get_locus (), + std::move (clobber.symbol))); + push (Rust::Token::make (COMMA, expr.get_locus ())); + } + push (Rust::Token::make (COLON, expr.get_locus ())); + // Dump options + + push (Rust::Token::make (RIGHT_PAREN, expr.get_locus ())); +} + // rust-item.h void @@ -2485,10 +2524,7 @@ TokenCollector::visit (StructPattern &pattern) void TokenCollector::visit (TupleStructItemsNoRange &pattern) { - for (auto &pat : pattern.get_patterns ()) - { - visit (pat); - } + visit_items_joined_by_separator (pattern.get_patterns ()); } void @@ -2591,6 +2627,13 @@ TokenCollector::visit (LetStmt &stmt) push (Rust::Token::make (EQUAL, UNDEF_LOCATION)); visit (stmt.get_init_expr ()); } + + if (stmt.has_else_expr ()) + { + push (Rust::Token::make (ELSE, UNDEF_LOCATION)); + visit (stmt.get_else_expr ()); + } + push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION)); } diff --git a/gcc/rust/ast/rust-ast-collector.h b/gcc/rust/ast/rust-ast-collector.h index b2dc41b..f45e3cc 100644 --- a/gcc/rust/ast/rust-ast-collector.h +++ b/gcc/rust/ast/rust-ast-collector.h @@ -210,7 +210,6 @@ public: void visit (TupleField &field); void visit (StructField &field); void visit (SimplePathSegment &segment); - void visit (NamedFunctionParam ¶m); void visit (MacroRule &rule); void visit (WhereClause &rule); void visit (std::vector<LifetimeParam> &for_lifetimes); @@ -304,6 +303,7 @@ public: void visit (AwaitExpr &expr); void visit (AsyncBlockExpr &expr); void visit (InlineAsm &expr); + void visit (LlvmInlineAsm &expr); // rust-item.h void visit (TypeParam ¶m); void visit (LifetimeWhereClauseItem &item); diff --git a/gcc/rust/ast/rust-ast-full-decls.h b/gcc/rust/ast/rust-ast-full-decls.h index d2ba876..9359248 100644 --- a/gcc/rust/ast/rust-ast-full-decls.h +++ b/gcc/rust/ast/rust-ast-full-decls.h @@ -61,7 +61,7 @@ class PathIdentSegment; struct GenericArgsBinding; struct GenericArgs; class PathExprSegment; -class PathPattern; +class Path; class PathInExpression; class TypePathSegment; class TypePathSegmentGeneric; @@ -148,7 +148,7 @@ class AsyncBlockExpr; enum class InlineAsmOption; struct AnonConst; struct InlineAsmRegOrRegClass; -struct InlineAsmOperand; +class InlineAsmOperand; struct InlineAsmPlaceHolder; struct InlineAsmTemplatePiece; struct TupleClobber; @@ -202,7 +202,6 @@ class TraitImpl; class ExternalItem; class ExternalTypeItem; class ExternalStaticItem; -class NamedFunctionParam; class ExternBlock; // rust-macro.h diff --git a/gcc/rust/ast/rust-ast-visitor.cc b/gcc/rust/ast/rust-ast-visitor.cc index 866357b..b6833f6 100644 --- a/gcc/rust/ast/rust-ast-visitor.cc +++ b/gcc/rust/ast/rust-ast-visitor.cc @@ -82,15 +82,17 @@ DefaultASTVisitor::visit (AST::ConstGenericParam &const_param) if (const_param.has_type ()) visit (const_param.get_type ()); if (const_param.has_default_value ()) - visit (const_param.get_default_value ()); + visit (const_param.get_default_value_unchecked ()); } void DefaultASTVisitor::visit (AST::PathInExpression &path) { visit_outer_attrs (path); - for (auto &segment : path.get_segments ()) - visit (segment); + + if (!path.is_lang_item ()) + for (auto &segment : path.get_segments ()) + visit (segment); } void @@ -106,7 +108,8 @@ DefaultASTVisitor::visit (GenericArgsBinding &binding) void DefaultASTVisitor::visit (AST::TypePathSegmentGeneric &segment) { - visit (segment.get_generic_args ()); + if (segment.has_generic_args ()) + visit (segment.get_generic_args ()); } void @@ -390,6 +393,7 @@ DefaultASTVisitor::visit (AST::StructExprStructFields &expr) { visit_outer_attrs (expr); visit_inner_attrs (expr); + visit (expr.get_struct_name ()); if (expr.has_struct_base ()) visit (expr.get_struct_base ()); for (auto &field : expr.get_fields ()) @@ -401,6 +405,7 @@ DefaultASTVisitor::visit (AST::StructExprStructBase &expr) { visit_outer_attrs (expr); visit_inner_attrs (expr); + visit (expr.get_struct_name ()); visit (expr.get_struct_base ()); } @@ -473,7 +478,8 @@ void DefaultASTVisitor::visit (AST::ContinueExpr &expr) { visit_outer_attrs (expr); - visit (expr.get_label ()); + if (expr.has_label ()) + visit (expr.get_label_unchecked ()); } void @@ -481,7 +487,7 @@ DefaultASTVisitor::visit (AST::BreakExpr &expr) { visit_outer_attrs (expr); if (expr.has_label ()) - visit (expr.get_label ()); + visit (expr.get_label_unchecked ()); if (expr.has_break_expr ()) visit (expr.get_break_expr ()); @@ -555,7 +561,8 @@ void DefaultASTVisitor::visit (AST::LoopExpr &expr) { visit_outer_attrs (expr); - visit (expr.get_loop_label ()); + if (expr.has_loop_label ()) + visit (expr.get_loop_label ()); visit (expr.get_loop_block ()); } @@ -563,8 +570,9 @@ void DefaultASTVisitor::visit (AST::WhileLoopExpr &expr) { visit_outer_attrs (expr); + if (expr.has_loop_label ()) + visit (expr.get_loop_label ()); visit (expr.get_predicate_expr ()); - visit (expr.get_loop_label ()); visit (expr.get_loop_block ()); } @@ -574,8 +582,8 @@ DefaultASTVisitor::visit (AST::WhileLetLoopExpr &expr) visit_outer_attrs (expr); for (auto &pattern : expr.get_patterns ()) visit (pattern); - visit (expr.get_scrutinee_expr ()); visit (expr.get_loop_label ()); + visit (expr.get_scrutinee_expr ()); visit (expr.get_loop_block ()); } @@ -585,7 +593,8 @@ DefaultASTVisitor::visit (AST::ForLoopExpr &expr) visit_outer_attrs (expr); visit (expr.get_pattern ()); visit (expr.get_iterator_expr ()); - visit (expr.get_loop_label ()); + if (expr.has_loop_label ()) + visit (expr.get_loop_label ()); visit (expr.get_loop_block ()); } @@ -664,7 +673,56 @@ DefaultASTVisitor::visit (AST::AsyncBlockExpr &expr) void DefaultASTVisitor::visit (AST::InlineAsm &expr) -{} +{ + visit_outer_attrs (expr); + using RegisterType = AST::InlineAsmOperand::RegisterType; + for (auto &operand : expr.get_operands ()) + { + switch (operand.get_register_type ()) + { + case RegisterType::In: { + visit (operand.get_in ().expr); + break; + } + case RegisterType::Out: { + visit (operand.get_out ().expr); + break; + } + case RegisterType::InOut: { + visit (operand.get_in_out ().expr); + break; + } + case RegisterType::SplitInOut: { + auto split = operand.get_split_in_out (); + visit (split.in_expr); + visit (split.out_expr); + break; + } + case RegisterType::Const: { + visit (operand.get_const ().anon_const.expr); + break; + } + case RegisterType::Sym: { + visit (operand.get_sym ().expr); + break; + } + case RegisterType::Label: { + visit (operand.get_label ().expr); + break; + } + } + } +} + +void +DefaultASTVisitor::visit (AST::LlvmInlineAsm &expr) +{ + for (auto &output : expr.get_outputs ()) + visit (output.expr); + + for (auto &input : expr.get_inputs ()) + visit (input.expr); +} void DefaultASTVisitor::visit (AST::TypeParam ¶m) @@ -770,10 +828,18 @@ DefaultASTVisitor::visit (AST::UseTreeRebind &use_tree) void DefaultASTVisitor::visit (AST::UseDeclaration &use_decl) { + visit (use_decl.get_visibility ()); visit (use_decl.get_tree ()); } void +DefaultASTVisitor::visit_function_params (AST::Function &function) +{ + for (auto ¶m : function.get_function_params ()) + visit (param); +} + +void DefaultASTVisitor::visit (AST::Function &function) { visit_outer_attrs (function); @@ -781,10 +847,9 @@ DefaultASTVisitor::visit (AST::Function &function) visit (function.get_qualifiers ()); for (auto &generic : function.get_generic_params ()) visit (generic); - if (function.has_self_param ()) - visit (function.get_self_param ()); - for (auto ¶m : function.get_function_params ()) - visit (param); + + visit_function_params (function); + if (function.has_return_type ()) visit (function.get_return_type ()); if (function.has_where_clause ()) @@ -947,6 +1012,8 @@ DefaultASTVisitor::visit (AST::Trait &trait) visit_inner_attrs (trait); + visit (trait.get_implicit_self ()); + for (auto &generic : trait.get_generic_params ()) visit (generic); @@ -987,6 +1054,7 @@ DefaultASTVisitor::visit (AST::TraitImpl &impl) if (impl.has_where_clause ()) visit (impl.get_where_clause ()); visit (impl.get_type ()); + visit (impl.get_trait_path ()); visit_inner_attrs (impl); for (auto &item : impl.get_impl_items ()) visit (item); @@ -1008,14 +1076,6 @@ DefaultASTVisitor::visit (AST::ExternalStaticItem &item) } void -DefaultASTVisitor::visit (AST::NamedFunctionParam ¶m) -{ - visit_outer_attrs (param); - if (!param.is_variadic ()) - visit (param.get_type ()); -} - -void DefaultASTVisitor::visit (AST::ExternBlock &block) { visit_outer_attrs (block); @@ -1403,33 +1463,33 @@ DefaultASTVisitor::visit (AST::VariadicParam ¶m) void ContextualASTVisitor::visit (AST::Crate &crate) { - push_context (Context::CRATE); + ctx.enter (Kind::CRATE); DefaultASTVisitor::visit (crate); - pop_context (); + ctx.exit (); } void ContextualASTVisitor::visit (AST::InherentImpl &impl) { - push_context (Context::INHERENT_IMPL); + ctx.enter (Kind::INHERENT_IMPL); DefaultASTVisitor::visit (impl); - pop_context (); + ctx.exit (); } void ContextualASTVisitor::visit (AST::TraitImpl &impl) { - push_context (Context::TRAIT_IMPL); + ctx.enter (Kind::TRAIT_IMPL); DefaultASTVisitor::visit (impl); - pop_context (); + ctx.exit (); } void ContextualASTVisitor::visit (AST::Trait &trait) { - push_context (Context::TRAIT); + ctx.enter (Kind::TRAIT); DefaultASTVisitor::visit (trait); - pop_context (); + ctx.exit (); } } // namespace AST diff --git a/gcc/rust/ast/rust-ast-visitor.h b/gcc/rust/ast/rust-ast-visitor.h index 2f56d89..b1fc504 100644 --- a/gcc/rust/ast/rust-ast-visitor.h +++ b/gcc/rust/ast/rust-ast-visitor.h @@ -24,7 +24,9 @@ #include "rust-ast-full-decls.h" #include "rust-ast.h" #include "rust-item.h" +#include "rust-path.h" #include "rust-system.h" +#include "rust-stacked-contexts.h" namespace Rust { namespace AST { @@ -129,6 +131,7 @@ public: virtual void visit (AwaitExpr &expr) = 0; virtual void visit (AsyncBlockExpr &expr) = 0; virtual void visit (InlineAsm &expr) = 0; + virtual void visit (LlvmInlineAsm &expr) = 0; // rust-item.h virtual void visit (TypeParam ¶m) = 0; @@ -239,9 +242,10 @@ public: class DefaultASTVisitor : public ASTVisitor { public: + virtual void visit_function_params (AST::Function &function); + virtual void visit (AST::Crate &crate); -protected: virtual void visit (AST::Token &tok) override; virtual void visit (AST::DelimTokenTree &delim_tok_tree) override; virtual void visit (AST::AttrInputMetaItemContainer &input) override; @@ -313,6 +317,7 @@ protected: virtual void visit (AST::AwaitExpr &expr) override; virtual void visit (AST::AsyncBlockExpr &expr) override; virtual void visit (InlineAsm &expr) override; + virtual void visit (LlvmInlineAsm &expr) override; virtual void visit (AST::TypeParam ¶m) override; virtual void visit (AST::LifetimeWhereClauseItem &item) override; @@ -423,7 +428,6 @@ protected: virtual void visit (AST::WhereClause &where); virtual void visit (AST::StructField &field); virtual void visit (AST::TupleField &field); - virtual void visit (AST::NamedFunctionParam ¶m); virtual void visit (AST::MacroRule &rule); virtual void visit (AST::MacroInvocData &data); virtual void visit (AST::MacroTranscriber &transcriber); @@ -448,7 +452,7 @@ protected: class ContextualASTVisitor : public DefaultASTVisitor { protected: - enum class Context + enum class Kind { FUNCTION, INHERENT_IMPL, @@ -457,6 +461,7 @@ protected: MODULE, CRATE, }; + using DefaultASTVisitor::visit; virtual void visit (AST::Crate &crate) override; @@ -472,11 +477,7 @@ protected: DefaultASTVisitor::visit (item); } - std::vector<Context> context; - - void push_context (Context ctx) { context.push_back (ctx); } - - void pop_context () { context.pop_back (); } + StackedContexts<Kind> ctx; }; } // namespace AST diff --git a/gcc/rust/ast/rust-ast.cc b/gcc/rust/ast/rust-ast.cc index bf7d31d..4e82be4 100644 --- a/gcc/rust/ast/rust-ast.cc +++ b/gcc/rust/ast/rust-ast.cc @@ -272,8 +272,8 @@ Attribute::get_traits_to_derive () case AST::MetaItem::ItemKind::Word: { auto word = static_cast<AST::MetaWord *> (meta_item); // Convert current word to path - current - = make_unique<AST::MetaItemPath> (AST::MetaItemPath ( + current = std::make_unique<AST::MetaItemPath> ( + AST::MetaItemPath ( AST::SimplePath (word->get_ident ()))); auto path = static_cast<AST::MetaItemPath *> (current.get ()); @@ -311,7 +311,8 @@ Attribute::get_traits_to_derive () // Copy constructor must deep copy attr_input as unique pointer Attribute::Attribute (Attribute const &other) - : path (other.path), locus (other.locus) + : path (other.path), locus (other.locus), + inner_attribute (other.inner_attribute) { // guard to protect from null pointer dereference if (other.attr_input != nullptr) @@ -324,6 +325,7 @@ Attribute::operator= (Attribute const &other) { path = other.path; locus = other.locus; + inner_attribute = other.inner_attribute; // guard to protect from null pointer dereference if (other.attr_input != nullptr) attr_input = other.attr_input->clone_attr_input (); @@ -1066,7 +1068,7 @@ Function::Function (Function const &other) : VisItem (other), ExternalItem (other.get_node_id ()), qualifiers (other.qualifiers), function_name (other.function_name), where_clause (other.where_clause), locus (other.locus), - is_default (other.is_default), + has_default (other.has_default), is_external_function (other.is_external_function) { // guard to prevent null dereference (always required) @@ -1098,7 +1100,7 @@ Function::operator= (Function const &other) // visibility = other.visibility->clone_visibility(); // outer_attrs = other.outer_attrs; locus = other.locus; - is_default = other.is_default; + has_default = other.has_default; is_external_function = other.is_external_function; // guard to prevent null dereference (always required) @@ -1629,7 +1631,7 @@ ContinueExpr::as_string () const std::string str ("continue "); if (has_label ()) - str += label.as_string (); + str += get_label_unchecked ().as_string (); return str; } @@ -2093,7 +2095,7 @@ WhileLoopExpr::as_string () const if (!has_loop_label ()) str += "none"; else - str += loop_label.as_string (); + str += get_loop_label ().as_string (); str += "\n Conditional expr: " + condition->as_string (); @@ -2113,7 +2115,7 @@ WhileLetLoopExpr::as_string () const if (!has_loop_label ()) str += "none"; else - str += loop_label.as_string (); + str += get_loop_label ().as_string (); str += "\n Match arm patterns: "; if (match_arm_patterns.empty ()) @@ -2144,7 +2146,7 @@ LoopExpr::as_string () const if (!has_loop_label ()) str += "none"; else - str += loop_label.as_string (); + str += get_loop_label ().as_string (); str += "\n Loop block: " + loop_block->as_string (); @@ -2181,7 +2183,7 @@ BreakExpr::as_string () const std::string str ("break "); if (has_label ()) - str += label.as_string () + " "; + str += get_label_unchecked ().as_string () + " "; if (has_break_expr ()) str += break_expr->as_string (); @@ -2483,9 +2485,6 @@ MacroMatchRepetition::as_string () const std::string Lifetime::as_string () const { - if (is_error ()) - return "error lifetime"; - switch (lifetime_type) { case NAMED: @@ -2543,7 +2542,7 @@ ForLoopExpr::as_string () const if (!has_loop_label ()) str += "none"; else - str += loop_label.as_string (); + str += get_loop_label ().as_string (); str += "\n Pattern: " + pattern->as_string (); @@ -2610,7 +2609,7 @@ ReferenceType::as_string () const std::string str ("&"); if (has_lifetime ()) - str += lifetime.as_string () + " "; + str += get_lifetime ().as_string () + " "; if (has_mut) str += "mut "; @@ -2996,22 +2995,6 @@ ExternalStaticItem::as_string () const } std::string -NamedFunctionParam::as_string () const -{ - std::string str = append_attributes (outer_attrs, OUTER); - - if (has_name ()) - str += "\n" + name; - - if (is_variadic ()) - str += "..."; - else - str += "\n Type: " + param_type->as_string (); - - return str; -} - -std::string TraitItemConst::as_string () const { // TODO: rewrite to work with non-linearisable exprs @@ -3084,7 +3067,7 @@ SelfParam::as_string () const else if (has_lifetime ()) { // ref and lifetime - std::string str = "&" + lifetime.as_string () + " "; + std::string str = "&" + get_lifetime ().as_string () + " "; if (is_mut) str += "mut "; @@ -4284,7 +4267,7 @@ BlockExpr::normalize_tail_expr () if (!stmt.is_semicolon_followed ()) { - expr = std::move (stmt.take_expr ()); + expr = stmt.take_expr (); statements.pop_back (); } } @@ -4668,6 +4651,12 @@ InlineAsm::accept_vis (ASTVisitor &vis) } void +LlvmInlineAsm::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void TypeParam::accept_vis (ASTVisitor &vis) { vis.visit (*this); diff --git a/gcc/rust/ast/rust-ast.h b/gcc/rust/ast/rust-ast.h index 4f40eff..aa6ad50 100644 --- a/gcc/rust/ast/rust-ast.h +++ b/gcc/rust/ast/rust-ast.h @@ -57,6 +57,11 @@ public: bool empty () const { return ident.empty (); } + bool operator== (const Identifier &other) const + { + return ident == other.ident; + } + private: std::string ident; location_t loc; @@ -70,16 +75,6 @@ namespace AST { class ASTVisitor; using AttrVec = std::vector<Attribute>; -// The available kinds of AST Nodes -enum class Kind -{ - UNKNOWN, - MODULE, - MACRO_RULES_DEFINITION, - MACRO_INVOCATION, - IDENTIFIER, -}; - class Visitable { public: @@ -87,20 +82,6 @@ public: virtual void accept_vis (ASTVisitor &vis) = 0; }; -// Abstract base class for all AST elements -class Node : public Visitable -{ -public: - /** - * Get the kind of Node this is. This is used to differentiate various AST - * elements with very little overhead when extracting the derived type - * through static casting is not necessary. - */ - // FIXME: Mark this as `= 0` in the future to make sure every node - // implements it - virtual Kind get_ast_kind () const { return Kind::UNKNOWN; } -}; - // Delimiter types - used in macros and whatever. enum DelimType { @@ -681,6 +662,9 @@ public: // Returns whether the attribute is considered an "empty" attribute. bool is_empty () const { return attr_input == nullptr && path.is_empty (); } + // Returns whether the attribute has no input + bool empty_input () const { return !attr_input; } + location_t get_locus () const { return locus; } AttrInput &get_attr_input () const { return *attr_input; } @@ -1039,6 +1023,7 @@ public: } DelimType get_delim_type () const { return delim_type; } + location_t get_locus () const { return locus; } }; /* Forward decl - definition moved to rust-expr.h as it requires LiteralExpr @@ -1092,7 +1077,7 @@ class MetaListNameValueStr; /* Base statement abstract class. Note that most "statements" are not allowed * in top-level module scope - only a subclass of statements called "items" * are. */ -class Stmt : public Node +class Stmt : public Visitable { public: enum class Kind @@ -1141,6 +1126,28 @@ protected: class Item : public Stmt { public: + enum class Kind + { + MacroRulesDefinition, + MacroInvocation, + Module, + ExternCrate, + UseDeclaration, + Function, + TypeAlias, + Struct, + EnumItem, + Enum, + Union, + ConstantItem, + StaticItem, + Trait, + Impl, + ExternBlock, + }; + + virtual Kind get_item_kind () const = 0; + // Unique pointer custom clone function std::unique_ptr<Item> clone_item () const { @@ -1221,14 +1228,65 @@ public: { return outer_attrs; } + + virtual Item::Kind get_item_kind () const override = 0; }; + // forward decl of ExprWithoutBlock class ExprWithoutBlock; // Base expression AST node - abstract -class Expr : public Node +class Expr : public Visitable { public: + enum class Kind + { + PathInExpression, + QualifiedPathInExpression, + Literal, + Operator, + Grouped, + Array, + ArrayIndex, + Tuple, + TupleIndex, + Struct, + Call, + MethodCall, + FieldAccess, + Closure, + Block, + Continue, + Break, + Range, + Box, + Return, + UnsafeBlock, + Loop, + If, + IfLet, + Match, + Await, + AsyncBlock, + InlineAsm, + LlvmInlineAsm, + Identifier, + FormatArgs, + MacroInvocation, + Borrow, + Dereference, + ErrorPropagation, + Negation, + ArithmeticOrLogical, + Comparison, + LazyBoolean, + TypeCast, + Assignment, + CompoundAssignment, + }; + + virtual Kind get_expr_kind () const = 0; + // Unique pointer custom clone function std::unique_ptr<Expr> clone_expr () const { @@ -1343,7 +1401,7 @@ public: outer_attrs = std::move (new_attrs); } - Kind get_ast_kind () const override { return Kind::IDENTIFIER; } + Expr::Kind get_expr_kind () const override { return Expr::Kind::Identifier; } protected: // Clone method implementation @@ -1410,7 +1468,7 @@ protected: class TraitBound; // Base class for types as represented in AST - abstract -class Type : public Node +class Type : public Visitable { public: // Unique pointer custom clone function @@ -1477,6 +1535,12 @@ protected: class TypeParamBound : public Visitable { public: + enum TypeParamBoundType + { + TRAIT, + LIFETIME + }; + virtual ~TypeParamBound () {} // Unique pointer custom clone function @@ -1491,6 +1555,8 @@ public: virtual location_t get_locus () const = 0; + virtual TypeParamBoundType get_bound_type () const = 0; + protected: // Clone function implementation as pure virtual method virtual TypeParamBound *clone_type_param_bound_impl () const = 0; @@ -1531,27 +1597,24 @@ public: lifetime_name (std::move (name)), locus (locus) {} - // Creates an "error" lifetime. - static Lifetime error () { return Lifetime (NAMED, ""); } - static Lifetime elided () { return Lifetime (WILDCARD, ""); } // Returns true if the lifetime is in an error state. - bool is_error () const - { - return lifetime_type == NAMED && lifetime_name.empty (); - } - std::string as_string () const override; void accept_vis (ASTVisitor &vis) override; - LifetimeType get_lifetime_type () { return lifetime_type; } + LifetimeType get_lifetime_type () const { return lifetime_type; } location_t get_locus () const override final { return locus; } std::string get_lifetime_name () const { return lifetime_name; } + TypeParamBoundType get_bound_type () const override + { + return TypeParamBound::TypeParamBoundType::LIFETIME; + } + protected: /* Use covariance to implement clone function as returning this object * rather than base */ @@ -1587,7 +1650,7 @@ public: virtual Kind get_kind () const = 0; - NodeId get_node_id () { return node_id; } + NodeId get_node_id () const { return node_id; } protected: GenericParam () : node_id (Analysis::Mappings::get ().get_next_node_id ()) {} @@ -1619,17 +1682,13 @@ public: std::vector<Lifetime> &get_lifetime_bounds () { return lifetime_bounds; } - // Returns whether the lifetime param has an outer attribute. - bool has_outer_attribute () const { return !outer_attrs.empty (); } - - // Creates an error state lifetime param. - static LifetimeParam create_error () + const std::vector<Lifetime> &get_lifetime_bounds () const { - return LifetimeParam (Lifetime::error (), {}, {}, UNDEF_LOCATION); + return lifetime_bounds; } - // Returns whether the lifetime param is in an error state. - bool is_error () const { return lifetime.is_error (); } + // Returns whether the lifetime param has an outer attribute. + bool has_outer_attribute () const { return !outer_attrs.empty (); } // Constructor LifetimeParam (Lifetime lifetime, std::vector<Lifetime> lifetime_bounds, @@ -1930,13 +1989,6 @@ public: return std::move (item); } - std::unique_ptr<AssociatedItem> take_trait_item () - { - rust_assert (!is_error ()); - return std::unique_ptr<AssociatedItem> ( - static_cast<AssociatedItem *> (assoc_item.release ())); - } - std::unique_ptr<ExternalItem> take_external_item () { rust_assert (!is_error ()); @@ -1949,16 +2001,6 @@ public: return std::move (assoc_item); } - std::unique_ptr<AssociatedItem> take_impl_item () - { - return take_assoc_item (); - } - - std::unique_ptr<AssociatedItem> take_trait_impl_item () - { - return take_assoc_item (); - } - std::unique_ptr<Type> take_type () { rust_assert (!is_error ()); @@ -2048,11 +2090,6 @@ public: } }; -// Base path expression AST node - abstract -class PathExpr : public ExprWithoutBlock -{ -}; - } // namespace AST } // namespace Rust @@ -2065,6 +2102,19 @@ template <> struct less<Rust::Identifier> return lhs.as_string () < rhs.as_string (); } }; + +template <> struct hash<Rust::Identifier> +{ + std::size_t operator() (const Rust::Identifier &k) const + { + using std::hash; + using std::size_t; + using std::string; + + return hash<string> () (k.as_string ()) ^ (hash<int> () (k.get_locus ())); + } +}; + } // namespace std #endif diff --git a/gcc/rust/ast/rust-builtin-ast-nodes.h b/gcc/rust/ast/rust-builtin-ast-nodes.h index 7ebd656..3684092 100644 --- a/gcc/rust/ast/rust-builtin-ast-nodes.h +++ b/gcc/rust/ast/rust-builtin-ast-nodes.h @@ -202,6 +202,8 @@ public: const FormatArguments &get_arguments () const { return arguments; } virtual location_t get_locus () const override; + Expr::Kind get_expr_kind () const override { return Expr::Kind::FormatArgs; } + private: location_t loc; // FIXME: This probably needs to be a separate type - it is one in rustc's diff --git a/gcc/rust/ast/rust-collect-lang-items.cc b/gcc/rust/ast/rust-collect-lang-items.cc new file mode 100644 index 0000000..cd6be7f --- /dev/null +++ b/gcc/rust/ast/rust-collect-lang-items.cc @@ -0,0 +1,113 @@ +// Copyright (C) 2024 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-collect-lang-items.h" +#include "optional.h" +#include "rust-ast-collector.h" +#include "rust-ast-visitor.h" +#include "rust-ast.h" +#include "rust-attribute-values.h" +#include "rust-attributes.h" +#include "rust-hir-map.h" +#include "rust-item.h" + +namespace Rust { +namespace AST { + +template <typename T> +tl::optional<LangItem::Kind> +get_lang_item_attr (const T &maybe_lang_item) +{ + for (const auto &attr : maybe_lang_item.get_outer_attrs ()) + { + const auto &str_path = attr.get_path ().as_string (); + if (!Analysis::Attributes::is_known (str_path)) + { + rust_error_at (attr.get_locus (), "unknown attribute %qs", + str_path.c_str ()); + continue; + } + + bool is_lang_item = str_path == Values::Attributes::LANG + && attr.has_attr_input () + && attr.get_attr_input ().get_attr_input_type () + == AST::AttrInput::AttrInputType::LITERAL; + + if (is_lang_item) + { + auto &literal + = static_cast<AST::AttrInputLiteral &> (attr.get_attr_input ()); + const auto &lang_item_type_str = literal.get_literal ().as_string (); + + return LangItem::Parse (lang_item_type_str); + } + } + + return tl::nullopt; +} + +template <typename T> +void +CollectLangItems::maybe_add_lang_item (const T &item) +{ + if (auto lang_item = get_lang_item_attr (item)) + mappings.insert_lang_item_node (lang_item.value (), item.get_node_id ()); +} + +void +CollectLangItems::visit (AST::Trait &item) +{ + maybe_add_lang_item (item); + + DefaultASTVisitor::visit (item); +} + +void +CollectLangItems::visit (AST::TraitItemType &item) +{ + maybe_add_lang_item (item); + + DefaultASTVisitor::visit (item); +} + +void +CollectLangItems::visit (AST::Function &item) +{ + maybe_add_lang_item (item); + + DefaultASTVisitor::visit (item); +} + +void +CollectLangItems::visit (AST::StructStruct &item) +{ + maybe_add_lang_item (item); + + DefaultASTVisitor::visit (item); +} + +void +CollectLangItems::visit (AST::EnumItem &item) +{ + maybe_add_lang_item (item); + + DefaultASTVisitor::visit (item); +} + +} // namespace AST +} // namespace Rust diff --git a/gcc/rust/ast/rust-collect-lang-items.h b/gcc/rust/ast/rust-collect-lang-items.h new file mode 100644 index 0000000..ddb34a9 --- /dev/null +++ b/gcc/rust/ast/rust-collect-lang-items.h @@ -0,0 +1,61 @@ +// Copyright (C) 2024 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_COLLECT_LANG_ITEMS_H +#define RUST_COLLECT_LANG_ITEMS_H + +#include "rust-ast-visitor.h" +#include "rust-ast.h" +#include "rust-hir-map.h" +#include "rust-item.h" + +namespace Rust { +namespace AST { + +// This class collects lang items ahead of lowering, as they are now needed for +// some parts of name resolution +class CollectLangItems : public DefaultASTVisitor +{ +public: + CollectLangItems () : mappings (Analysis::Mappings::get ()){}; + + void go (AST::Crate &crate) { DefaultASTVisitor::visit (crate); } + + Analysis::Mappings &mappings; + + // We must implement visitors for all constructs that could be lang items. + // Lang items can be traits, but also enums, and even enum variants. + // + // https://github.com/rust-lang/rust/blob/master/compiler/rustc_hir/src/lang_items.rs + + using DefaultASTVisitor::visit; + + void visit (AST::Trait &item) override; + void visit (AST::TraitItemType &item) override; + void visit (AST::Function &item) override; + void visit (AST::StructStruct &item) override; + void visit (AST::EnumItem &item) override; + +private: + template <typename T> void maybe_add_lang_item (const T &item); +}; + +} // namespace AST +} // namespace Rust + +#endif // ! RUST_COLLECT_LANG_ITEMS_H diff --git a/gcc/rust/ast/rust-desugar-for-loops.cc b/gcc/rust/ast/rust-desugar-for-loops.cc new file mode 100644 index 0000000..ffc3470 --- /dev/null +++ b/gcc/rust/ast/rust-desugar-for-loops.cc @@ -0,0 +1,204 @@ +// Copyright (C) 2025 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-desugar-for-loops.h" +#include "rust-ast-visitor.h" +#include "rust-ast.h" +#include "rust-hir-map.h" +#include "rust-path.h" +#include "rust-pattern.h" +#include "rust-stmt.h" +#include "rust-expr.h" +#include "rust-ast-builder.h" + +namespace Rust { +namespace AST { + +DesugarForLoops::DesugarForLoops () {} + +void +DesugarForLoops::go (AST::Crate &crate) +{ + DefaultASTVisitor::visit (crate); +} + +static void +replace_for_loop (std::unique_ptr<Expr> &for_loop, + std::unique_ptr<Expr> &&expanded) +{ + for_loop = std::move (expanded); +} + +MatchArm +DesugarForLoops::DesugarCtx::make_match_arm (std::unique_ptr<Pattern> &&path) +{ + auto patterns = std::vector<std::unique_ptr<Pattern>> (); + patterns.emplace_back (std::move (path)); + + return MatchArm (std::move (patterns), loc); +} + +MatchCase +DesugarForLoops::DesugarCtx::make_break_arm () +{ + auto arm = make_match_arm (std::unique_ptr<Pattern> (new PathInExpression ( + builder.path_in_expression (LangItem::Kind::OPTION_NONE)))); + + auto break_expr + = std::unique_ptr<Expr> (new BreakExpr (tl::nullopt, nullptr, {}, loc)); + + return MatchCase (std::move (arm), std::move (break_expr)); +} + +MatchCase +DesugarForLoops::DesugarCtx::make_continue_arm () +{ + auto val = builder.identifier_pattern (DesugarCtx::continue_pattern_id); + + auto patterns = std::vector<std::unique_ptr<Pattern>> (); + patterns.emplace_back (std::move (val)); + + auto pattern_item = std::unique_ptr<TupleStructItems> ( + new TupleStructItemsNoRange (std::move (patterns))); + auto pattern = std::unique_ptr<Pattern> (new TupleStructPattern ( + builder.path_in_expression (LangItem::Kind::OPTION_SOME), + std::move (pattern_item))); + + auto val_arm = make_match_arm (std::move (pattern)); + + auto next = builder.identifier (DesugarCtx::next_value_id); + + auto assignment = std::unique_ptr<Expr> ( + new AssignmentExpr (std::move (next), + builder.identifier (DesugarCtx::continue_pattern_id), + {}, loc)); + + return MatchCase (std::move (val_arm), std::move (assignment)); +} + +std::unique_ptr<Stmt> +DesugarForLoops::DesugarCtx::statementify (std::unique_ptr<Expr> &&expr) +{ + return std::unique_ptr<Stmt> (new ExprStmt (std::move (expr), loc, true)); +} + +std::unique_ptr<Expr> +DesugarForLoops::desugar (AST::ForLoopExpr &expr) +{ + auto ctx = DesugarCtx (expr.get_locus ()); + + auto into_iter = std::make_unique<PathInExpression> ( + ctx.builder.path_in_expression (LangItem::Kind::INTOITER_INTOITER)); + auto next = std::make_unique<PathInExpression> ( + ctx.builder.path_in_expression (LangItem::Kind::ITERATOR_NEXT)); + + // IntoIterator::into_iter(<head>) + auto into_iter_call + = ctx.builder.call (std::move (into_iter), + expr.get_iterator_expr ().clone_expr ()); + + // Iterator::next(iter) + auto next_call = ctx.builder.call ( + std::move (next), + ctx.builder.ref (ctx.builder.identifier (DesugarCtx::iter_id), true)); + + // None => break, + auto break_arm = ctx.make_break_arm (); + // Some(val) => __next = val; }, + auto continue_arm = ctx.make_continue_arm (); + + // match <next_call> { + // <continue_arm> + // <break_arm> + // } + auto match_next + = ctx.builder.match (std::move (next_call), + {std::move (continue_arm), std::move (break_arm)}); + + // let mut __next; + auto let_next = ctx.builder.let ( + ctx.builder.identifier_pattern (DesugarCtx::next_value_id, true)); + // let <pattern> = __next; + auto let_pat + = ctx.builder.let (expr.get_pattern ().clone_pattern (), nullptr, + ctx.builder.identifier (DesugarCtx::next_value_id)); + + auto loop_stmts = std::vector<std::unique_ptr<Stmt>> (); + loop_stmts.emplace_back (std::move (let_next)); + loop_stmts.emplace_back (ctx.statementify (std::move (match_next))); + loop_stmts.emplace_back (std::move (let_pat)); + loop_stmts.emplace_back ( + ctx.statementify (expr.get_loop_block ().clone_expr ())); + + // loop { + // <let_next>; + // <match_next>; + // <let_pat>; + // + // <body>; + // } + auto loop = ctx.builder.loop (std::move (loop_stmts)); + + auto mut_iter_pattern + = ctx.builder.identifier_pattern (DesugarCtx::iter_id, true); + auto match_iter + = ctx.builder.match (std::move (into_iter_call), + {ctx.builder.match_case (std::move (mut_iter_pattern), + std::move (loop))}); + + auto let_result + = ctx.builder.let (ctx.builder.identifier_pattern (DesugarCtx::result_id), + nullptr, std::move (match_iter)); + auto result_return = ctx.builder.identifier (DesugarCtx::result_id); + + return ctx.builder.block (std::move (let_result), std::move (result_return)); +} + +void +DesugarForLoops::maybe_desugar_expr (std::unique_ptr<Expr> &expr) +{ + if (expr->get_expr_kind () == AST::Expr::Kind::Loop) + { + auto &loop = static_cast<AST::BaseLoopExpr &> (*expr); + + if (loop.get_loop_kind () == AST::BaseLoopExpr::Kind::For) + { + auto &for_loop = static_cast<AST::ForLoopExpr &> (loop); + + auto desugared = desugar (for_loop); + + replace_for_loop (expr, std::move (desugared)); + } + } +} + +void +DesugarForLoops::visit (AST::BlockExpr &block) +{ + for (auto &stmt : block.get_statements ()) + if (stmt->get_stmt_kind () == AST::Stmt::Kind::Expr) + maybe_desugar_expr (static_cast<AST::ExprStmt &> (*stmt).get_expr_ptr ()); + + if (block.has_tail_expr ()) + maybe_desugar_expr (block.get_tail_expr_ptr ()); + + DefaultASTVisitor::visit (block); +} + +} // namespace AST +} // namespace Rust diff --git a/gcc/rust/ast/rust-desugar-for-loops.h b/gcc/rust/ast/rust-desugar-for-loops.h new file mode 100644 index 0000000..7beb692 --- /dev/null +++ b/gcc/rust/ast/rust-desugar-for-loops.h @@ -0,0 +1,108 @@ +// Copyright (C) 2025 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_DESUGAR_FOR_LOOPS_H +#define RUST_DESUGAR_FOR_LOOPS_H + +#include "rust-ast-builder.h" +#include "rust-ast-visitor.h" +#include "rust-expr.h" + +namespace Rust { +namespace AST { + +// Desugar for-loops into a set of other AST nodes. The desugar is of the +// following form: +// +// ``` +// for <pat> in <head> <body> +// ``` +// +// becomes: +// +// ``` +// { +// let result = match ::std::iter::IntoIterator::into_iter(<head>) { +// mut iter => { +// loop { +// let mut __next; +// match ::std::iter::Iterator::next(&mut iter) { +// ::std::option::Option::Some(val) => __next = val, +// ::std::option::Option::None => break +// }; +// let <pat> = __next; +// +// <body>; +// } +// } +// }; +// result +// } +// ``` +// +// NOTE: In a perfect world, this would be an immutable visitor which would take +// ownership of the AST node and return a new one, instead of mutating this one +// in place. Nevertheless, this isn't Rust, and doing immutable visitors in C++ +// sucks, and the world isn't perfect, so we are impure and sad. +// +// NOTE: This class could eventually be removed in favor of +// an HIR desugar. This would avoid mutating the AST and would be cleaner. +// However, it requires multiple changes in the way we do typechecking and name +// resolution, as this desugar creates new bindings. Because of this, these new +// bindings need to be inserted into the name-resolution context outside of the +// name resolution pass, which is difficult. Those bindings are needed because +// of the way the typechecker is currently structured, where it will fetch name +// resolution information in order to typecheck paths - which technically isn't +// necessary. +class DesugarForLoops : public DefaultASTVisitor +{ + using DefaultASTVisitor::visit; + +public: + DesugarForLoops (); + void go (AST::Crate &); + +private: + struct DesugarCtx + { + DesugarCtx (location_t loc) : builder (Builder (loc)), loc (loc) {} + + Builder builder; + location_t loc; + + MatchArm make_match_arm (std::unique_ptr<Pattern> &&pattern); + MatchCase make_break_arm (); + MatchCase make_continue_arm (); + std::unique_ptr<Stmt> statementify (std::unique_ptr<Expr> &&expr); + + constexpr static const char *continue_pattern_id = "#val"; + constexpr static const char *next_value_id = "#__next"; + constexpr static const char *iter_id = "#iter"; + constexpr static const char *result_id = "#result"; + }; + + std::unique_ptr<Expr> desugar (AST::ForLoopExpr &expr); + void maybe_desugar_expr (std::unique_ptr<Expr> &expr); + + void visit (AST::BlockExpr &) override; +}; + +} // namespace AST +} // namespace Rust + +#endif // ! RUST_DESUGAR_FOR_LOOPS_H diff --git a/gcc/rust/ast/rust-desugar-question-mark.cc b/gcc/rust/ast/rust-desugar-question-mark.cc new file mode 100644 index 0000000..4d2933b --- /dev/null +++ b/gcc/rust/ast/rust-desugar-question-mark.cc @@ -0,0 +1,167 @@ +// Copyright (C) 2025 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-desugar-question-mark.h" +#include "rust-ast-builder.h" +#include "rust-ast-visitor.h" + +namespace Rust { +namespace AST { + +DesugarQuestionMark::DesugarQuestionMark () {} + +void +DesugarQuestionMark::go (AST::Crate &crate) +{ + DesugarQuestionMark::visit (crate); +} + +void +DesugarQuestionMark::visit (ExprStmt &stmt) +{ + if (stmt.get_expr ().get_expr_kind () == Expr::Kind::ErrorPropagation) + desugar_and_replace (stmt.get_expr_ptr ()); + + DefaultASTVisitor::visit (stmt); +} + +void +DesugarQuestionMark::visit (CallExpr &call) +{ + if (call.get_function_expr ().get_expr_kind () + == Expr::Kind::ErrorPropagation) + desugar_and_replace (call.get_function_expr_ptr ()); + + for (auto &arg : call.get_params ()) + if (arg->get_expr_kind () == Expr::Kind::ErrorPropagation) + desugar_and_replace (arg); + + DefaultASTVisitor::visit (call); +} + +void +DesugarQuestionMark::visit (LetStmt &stmt) +{ + if (stmt.has_init_expr () + && stmt.get_init_expr ().get_expr_kind () == Expr::Kind::ErrorPropagation) + desugar_and_replace (stmt.get_init_expr_ptr ()); + + DefaultASTVisitor::visit (stmt); +} + +MatchArm +make_match_arm (std::unique_ptr<Pattern> &&pattern) +{ + auto loc = pattern->get_locus (); + + auto patterns = std::vector<std::unique_ptr<Pattern>> (); + patterns.emplace_back (std::move (pattern)); + + return MatchArm (std::move (patterns), loc); +} + +MatchCase +ok_case (Builder &builder) +{ + auto val = builder.identifier_pattern ("val"); + + auto patterns = std::vector<std::unique_ptr<Pattern>> (); + patterns.emplace_back (std::move (val)); + + auto pattern_item = std::unique_ptr<TupleStructItems> ( + new TupleStructItemsNoRange (std::move (patterns))); + auto pattern = std::unique_ptr<Pattern> (new TupleStructPattern ( + builder.path_in_expression (LangItem::Kind::RESULT_OK), + std::move (pattern_item))); + + auto arm = make_match_arm (std::move (pattern)); + + auto ret_val = builder.identifier ("val"); + + return MatchCase (std::move (arm), std::move (ret_val)); +} + +MatchCase +err_case (Builder &builder) +{ + auto val = builder.identifier_pattern ("err"); + + auto patterns = std::vector<std::unique_ptr<Pattern>> (); + patterns.emplace_back (std::move (val)); + + auto pattern_item = std::unique_ptr<TupleStructItems> ( + new TupleStructItemsNoRange (std::move (patterns))); + auto pattern = std::unique_ptr<Pattern> (new TupleStructPattern ( + builder.path_in_expression (LangItem::Kind::RESULT_ERR), + std::move (pattern_item))); + + auto arm = make_match_arm (std::move (pattern)); + + auto try_from_err = std::make_unique<PathInExpression> ( + builder.path_in_expression (LangItem::Kind::TRY_FROM_ERROR)); + auto from_from = std::make_unique<PathInExpression> ( + builder.path_in_expression (LangItem::Kind::FROM_FROM)); + + auto early_return = builder.return_expr ( + builder.call (std::move (try_from_err), + builder.call (std::move (from_from), + builder.identifier ("err")))); + + return MatchCase (std::move (arm), std::move (early_return)); +} + +std::unique_ptr<Expr> +DesugarQuestionMark::desugar (ErrorPropagationExpr &expr) +{ + auto builder = Builder (expr.get_locus ()); + + // Try::into_result(<expr>) + auto try_into = std::make_unique<PathInExpression> ( + builder.path_in_expression (LangItem::Kind::TRY_INTO_RESULT)); + auto call = builder.call (std::move (try_into), + expr.get_propagating_expr ().clone_expr ()); + + // Ok(val) => val, + auto ok_match_case = ok_case (builder); + // Err(err) => return Try::from_error(From::from(err)), + auto err_match_case = err_case (builder); + + auto cases = std::vector<MatchCase> (); + cases.emplace_back (ok_match_case); + cases.emplace_back (err_match_case); + + // match <call> { + // <ok_arm> + // <err_arm> + // } + return std::unique_ptr<MatchExpr> (new MatchExpr (std::move (call), + std::move (cases), {}, {}, + expr.get_locus ())); +} + +void +DesugarQuestionMark::desugar_and_replace (std::unique_ptr<Expr> &ptr) +{ + auto original = static_cast<ErrorPropagationExpr &> (*ptr); + auto desugared = desugar (original); + + ptr = std::move (desugared); +} + +} // namespace AST +} // namespace Rust diff --git a/gcc/rust/ast/rust-desugar-question-mark.h b/gcc/rust/ast/rust-desugar-question-mark.h new file mode 100644 index 0000000..e4c513f --- /dev/null +++ b/gcc/rust/ast/rust-desugar-question-mark.h @@ -0,0 +1,79 @@ +// Copyright (C) 2025 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_DESUGAR_QUESTION_MARK +#define RUST_DESUGAR_QUESTION_MARK + +#include "rust-ast-visitor.h" +#include "rust-expr.h" +#include "rust-stmt.h" + +namespace Rust { +namespace AST { + +// NOTE: One more complexity compare to desugaring for-loops is that we need to +// desugar every possible expression... should we do that during lowering +// instead? but would it get resolved and expanded etc? Not sure... + +// The goal of this desugar is to go from this: +// +// ``` +// <expr>? +// ``` +// +// to this: +// +// ``` +// match Try::into_result(<expr>) { +// Ok(val) => val, +// Err(err) => return Try::from_err(From::from(err)) +// } +// ``` +// +// We use lang items for almost everything, so the actual desugared code looks +// more like this: +// +// ``` +// match #[lang = "into_result"](<expr>) { +// #[lang = "Ok"](val) => val, +// #[lang = "Err"](err) => { +// return #[lang = "from_error"](#[lang ="from"](err)) +// } +// } +// ``` +class DesugarQuestionMark : public DefaultASTVisitor +{ + using DefaultASTVisitor::visit; + +public: + DesugarQuestionMark (); + void go (AST::Crate &); + +private: + void desugar_and_replace (std::unique_ptr<Expr> &ptr); + std::unique_ptr<Expr> desugar (ErrorPropagationExpr &); + + void visit (AST::ExprStmt &) override; + void visit (AST::CallExpr &) override; + void visit (AST::LetStmt &) override; +}; + +} // namespace AST +} // namespace Rust + +#endif // ! RUST_DESUGAR_QUESTION_MARK diff --git a/gcc/rust/ast/rust-expr.h b/gcc/rust/ast/rust-expr.h index 9477bf0..fdb6360 100644 --- a/gcc/rust/ast/rust-expr.h +++ b/gcc/rust/ast/rust-expr.h @@ -15,7 +15,7 @@ namespace AST { // Loop label expression AST node used with break and continue expressions // TODO: inline? -class LoopLabel /*: public Node*/ +class LoopLabel /*: public Visitable*/ { Lifetime label; // or type LIFETIME_OR_LABEL location_t locus; @@ -31,11 +31,6 @@ public: {} // Returns whether the LoopLabel is in an error state. - bool is_error () const { return label.is_error (); } - - // Creates an error state LoopLabel. - static LoopLabel error () { return LoopLabel (Lifetime::error ()); } - location_t get_locus () const { return locus; } Lifetime &get_lifetime () { return label; } @@ -117,6 +112,8 @@ public: outer_attrs = std::move (new_attrs); } + Expr::Kind get_expr_kind () const override { return Expr::Kind::Literal; } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -365,6 +362,8 @@ public: { outer_attrs = std::move (new_attrs); } + + Expr::Kind get_expr_kind () const override { return Expr::Kind::Operator; } }; /* Unary prefix & or &mut (or && and &&mut) borrow operator. Cannot be @@ -403,6 +402,8 @@ public: bool get_is_double_borrow () const { return double_borrow; } bool is_raw_borrow () const { return raw_borrow; } + Expr::Kind get_expr_kind () const override { return Expr::Kind::Borrow; } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -433,6 +434,8 @@ public: return *main_or_left_expr; } + Expr::Kind get_expr_kind () const override { return Expr::Kind::Dereference; } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -464,6 +467,11 @@ public: return *main_or_left_expr; } + Expr::Kind get_expr_kind () const override + { + return Expr::Kind::ErrorPropagation; + } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -507,6 +515,8 @@ public: return *main_or_left_expr; } + Expr::Kind get_expr_kind () const override { return Expr::Kind::Negation; } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -595,6 +605,11 @@ public: void visit_lhs (ASTVisitor &vis) { main_or_left_expr->accept_vis (vis); } void visit_rhs (ASTVisitor &vis) { right_expr->accept_vis (vis); } + Expr::Kind get_expr_kind () const override + { + return Expr::Kind::ArithmeticOrLogical; + } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -682,6 +697,8 @@ public: ExprType get_kind () { return expr_type; } + Expr::Kind get_expr_kind () const override { return Expr::Kind::Comparison; } + /* TODO: implement via a function call to std::cmp::PartialEq::eq(&op1, &op2) * maybe? */ protected: @@ -770,6 +787,8 @@ public: ExprType get_kind () { return expr_type; } + Expr::Kind get_expr_kind () const override { return Expr::Kind::LazyBoolean; } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -832,6 +851,8 @@ public: return *type_to_convert_to; } + Expr::Kind get_expr_kind () const override { return Expr::Kind::TypeCast; } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -910,6 +931,8 @@ public: return *right_expr; } + Expr::Kind get_expr_kind () const override { return Expr::Kind::Assignment; } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -996,6 +1019,11 @@ public: return right_expr; } + Expr::Kind get_expr_kind () const override + { + return Expr::Kind::CompoundAssignment; + } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -1090,6 +1118,8 @@ public: return expr_in_parens; } + Expr::Kind get_expr_kind () const override { return Expr::Kind::Grouped; } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -1319,6 +1349,8 @@ public: return internal_elements; } + Expr::Kind get_expr_kind () const override { return Expr::Kind::Array; } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -1424,6 +1456,8 @@ public: outer_attrs = std::move (new_attrs); } + Expr::Kind get_expr_kind () const override { return Expr::Kind::ArrayIndex; } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -1520,6 +1554,8 @@ public: bool is_unit () const { return tuple_elems.size () == 0; } + Expr::Kind get_expr_kind () const override { return Expr::Kind::Tuple; } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -1607,6 +1643,8 @@ public: outer_attrs = std::move (new_attrs); } + Expr::Kind get_expr_kind () const override { return Expr::Kind::TupleIndex; } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -1650,6 +1688,8 @@ public: { outer_attrs = std::move (new_attrs); } + + Expr::Kind get_expr_kind () const override { return Expr::Kind::Struct; } }; // Actual AST node of the struct creator (with no fields). Not abstract! @@ -2123,6 +2163,8 @@ public: return *function; } + std::unique_ptr<Expr> &get_function_expr_ptr () { return function; } + const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; } std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; } @@ -2131,6 +2173,8 @@ public: outer_attrs = std::move (new_attrs); } + Expr::Kind get_expr_kind () const override { return Expr::Kind::Call; } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -2234,6 +2278,8 @@ public: outer_attrs = std::move (new_attrs); } + Expr::Kind get_expr_kind () const override { return Expr::Kind::MethodCall; } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -2319,6 +2365,8 @@ public: outer_attrs = std::move (new_attrs); } + Expr::Kind get_expr_kind () const override { return Expr::Kind::FieldAccess; } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -2454,6 +2502,8 @@ public: } bool get_has_move () const { return has_move; } + + Expr::Kind get_expr_kind () const override { return Expr::Kind::Closure; } }; // Represents a non-type-specified closure expression AST node @@ -2535,7 +2585,7 @@ class BlockExpr : public ExprWithBlock std::vector<Attribute> inner_attrs; std::vector<std::unique_ptr<Stmt> > statements; std::unique_ptr<Expr> expr; - LoopLabel label; + tl::optional<LoopLabel> label; location_t start_locus; location_t end_locus; bool marked_for_strip = false; @@ -2552,8 +2602,9 @@ public: BlockExpr (std::vector<std::unique_ptr<Stmt> > block_statements, std::unique_ptr<Expr> block_expr, std::vector<Attribute> inner_attribs, - std::vector<Attribute> outer_attribs, LoopLabel label, - location_t start_locus, location_t end_locus) + std::vector<Attribute> outer_attribs, + tl::optional<LoopLabel> label, location_t start_locus, + location_t end_locus) : outer_attrs (std::move (outer_attribs)), inner_attrs (std::move (inner_attribs)), statements (std::move (block_statements)), expr (std::move (block_expr)), @@ -2672,8 +2723,10 @@ public: outer_attrs = std::move (new_attrs); } - bool has_label () { return !label.is_error (); } - LoopLabel &get_label () { return label; } + bool has_label () { return label.has_value (); } + LoopLabel &get_label () { return label.value (); } + + Expr::Kind get_expr_kind () const override { return Expr::Kind::Block; } protected: /* Use covariance to implement clone function as returning this object rather @@ -2791,7 +2844,7 @@ protected: class ContinueExpr : public ExprWithoutBlock { std::vector<Attribute> outer_attrs; - Lifetime label; + tl::optional<Lifetime> label; location_t locus; // TODO: find another way to store this to save memory? @@ -2801,11 +2854,11 @@ public: std::string as_string () const override; // Returns true if the continue expr has a label. - bool has_label () const { return !label.is_error (); } + bool has_label () const { return label.has_value (); } // Constructor for a ContinueExpr with a label. - ContinueExpr (Lifetime label, std::vector<Attribute> outer_attribs, - location_t locus) + ContinueExpr (tl::optional<Lifetime> label, + std::vector<Attribute> outer_attribs, location_t locus) : outer_attrs (std::move (outer_attribs)), label (std::move (label)), locus (locus) {} @@ -2826,7 +2879,13 @@ public: outer_attrs = std::move (new_attrs); } - Lifetime &get_label () { return label; } + Lifetime &get_label_unchecked () { return label.value (); } + const Lifetime &get_label_unchecked () const { return label.value (); } + + tl::optional<Lifetime> &get_label () { return label; } + const tl::optional<Lifetime> &get_label () const { return label; } + + Expr::Kind get_expr_kind () const override { return Expr::Kind::Continue; } protected: /* Use covariance to implement clone function as returning this object rather @@ -2842,7 +2901,7 @@ protected: class BreakExpr : public ExprWithoutBlock { std::vector<Attribute> outer_attrs; - LoopLabel label; + tl::optional<LoopLabel> label; std::unique_ptr<Expr> break_expr; location_t locus; @@ -2853,14 +2912,15 @@ public: std::string as_string () const override; // Returns whether the break expression has a label or not. - bool has_label () const { return !label.is_error (); } + bool has_label () const { return label.has_value (); } /* Returns whether the break expression has an expression used in the break or * not. */ bool has_break_expr () const { return break_expr != nullptr; } // Constructor for a break expression - BreakExpr (LoopLabel break_label, std::unique_ptr<Expr> expr_in_break, + BreakExpr (tl::optional<LoopLabel> break_label, + std::unique_ptr<Expr> expr_in_break, std::vector<Attribute> outer_attribs, location_t locus) : outer_attrs (std::move (outer_attribs)), label (std::move (break_label)), break_expr (std::move (expr_in_break)), locus (locus) @@ -2922,7 +2982,13 @@ public: outer_attrs = std::move (new_attrs); } - LoopLabel &get_label () { return label; } + LoopLabel &get_label_unchecked () { return label.value (); } + const LoopLabel &get_label_unchecked () const { return label.value (); } + + tl::optional<LoopLabel> &get_label () { return label; } + const tl::optional<LoopLabel> &get_label () const { return label; } + + Expr::Kind get_expr_kind () const override { return Expr::Kind::Break; } protected: /* Use covariance to implement clone function as returning this object rather @@ -2938,6 +3004,10 @@ class RangeExpr : public ExprWithoutBlock { location_t locus; + // Some visitors still check for attributes on RangeExprs, and they will need + // to be supported in the future - so keep that for now + std::vector<Attribute> empty_attributes = {}; + protected: // outer attributes not allowed before range expressions RangeExpr (location_t locus) : locus (locus) {} @@ -2947,15 +3017,13 @@ public: std::vector<Attribute> &get_outer_attrs () override final { - // RangeExpr cannot have any outer attributes - rust_assert (false); + return empty_attributes; } // should never be called - error if called - void set_outer_attrs (std::vector<Attribute> /* new_attrs */) override - { - rust_assert (false); - } + void set_outer_attrs (std::vector<Attribute> /* new_attrs */) override {} + + Expr::Kind get_expr_kind () const override { return Expr::Kind::Range; } }; // Range from (inclusive) and to (exclusive) expression AST node object @@ -3404,6 +3472,8 @@ public: return *expr; } + Expr::Kind get_expr_kind () const override { return Expr::Kind::Box; } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -3491,6 +3561,8 @@ public: outer_attrs = std::move (new_attrs); } + Expr::Kind get_expr_kind () const override { return Expr::Kind::Return; } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -3573,6 +3645,8 @@ public: outer_attrs = std::move (new_attrs); } + Expr::Kind get_expr_kind () const override { return Expr::Kind::UnsafeBlock; } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -3588,7 +3662,7 @@ class BaseLoopExpr : public ExprWithBlock protected: // protected to allow subclasses better use of them std::vector<Attribute> outer_attrs; - LoopLabel loop_label; + tl::optional<LoopLabel> loop_label; std::unique_ptr<BlockExpr> loop_block; private: @@ -3597,7 +3671,7 @@ private: protected: // Constructor for BaseLoopExpr BaseLoopExpr (std::unique_ptr<BlockExpr> loop_block, location_t locus, - LoopLabel loop_label = LoopLabel::error (), + tl::optional<LoopLabel> loop_label = tl::nullopt, std::vector<Attribute> outer_attribs = std::vector<Attribute> ()) : outer_attrs (std::move (outer_attribs)), @@ -3637,9 +3711,10 @@ protected: BaseLoopExpr &operator= (BaseLoopExpr &&other) = default; public: - bool has_loop_label () const { return !loop_label.is_error (); } + bool has_loop_label () const { return loop_label.has_value (); } - LoopLabel &get_loop_label () { return loop_label; } + LoopLabel &get_loop_label () { return loop_label.value (); } + const LoopLabel &get_loop_label () const { return loop_label.value (); } location_t get_locus () const override final { return locus; } @@ -3661,6 +3736,18 @@ public: { outer_attrs = std::move (new_attrs); } + + Expr::Kind get_expr_kind () const override { return Expr::Kind::Loop; } + + enum class Kind + { + Loop, + While, + WhileLet, + For + }; + + virtual Kind get_loop_kind () const = 0; }; // 'Loop' expression (i.e. the infinite loop) AST node @@ -3671,7 +3758,7 @@ public: // Constructor for LoopExpr LoopExpr (std::unique_ptr<BlockExpr> loop_block, location_t locus, - LoopLabel loop_label = LoopLabel::error (), + tl::optional<LoopLabel> loop_label = tl::nullopt, std::vector<Attribute> outer_attribs = std::vector<Attribute> ()) : BaseLoopExpr (std::move (loop_block), locus, std::move (loop_label), std::move (outer_attribs)) @@ -3679,6 +3766,11 @@ public: void accept_vis (ASTVisitor &vis) override; + BaseLoopExpr::Kind get_loop_kind () const override + { + return BaseLoopExpr::Kind::Loop; + } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -3699,7 +3791,7 @@ public: // Constructor for while loop with loop label WhileLoopExpr (std::unique_ptr<Expr> loop_condition, std::unique_ptr<BlockExpr> loop_block, location_t locus, - LoopLabel loop_label = LoopLabel::error (), + tl::optional<LoopLabel> loop_label = tl::nullopt, std::vector<Attribute> outer_attribs = std::vector<Attribute> ()) : BaseLoopExpr (std::move (loop_block), locus, std::move (loop_label), @@ -3737,6 +3829,11 @@ public: return *condition; } + BaseLoopExpr::Kind get_loop_kind () const override + { + return BaseLoopExpr::Kind::While; + } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -3760,7 +3857,7 @@ public: WhileLetLoopExpr (std::vector<std::unique_ptr<Pattern> > match_arm_patterns, std::unique_ptr<Expr> scrutinee, std::unique_ptr<BlockExpr> loop_block, location_t locus, - LoopLabel loop_label = LoopLabel::error (), + tl::optional<LoopLabel> loop_label = tl::nullopt, std::vector<Attribute> outer_attribs = std::vector<Attribute> ()) : BaseLoopExpr (std::move (loop_block), locus, std::move (loop_label), @@ -3820,6 +3917,11 @@ public: return match_arm_patterns; } + BaseLoopExpr::Kind get_loop_kind () const override + { + return BaseLoopExpr::Kind::WhileLet; + } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -3842,7 +3944,7 @@ public: ForLoopExpr (std::unique_ptr<Pattern> loop_pattern, std::unique_ptr<Expr> iterator_expr, std::unique_ptr<BlockExpr> loop_body, location_t locus, - LoopLabel loop_label = LoopLabel::error (), + tl::optional<LoopLabel> loop_label = tl::nullopt, std::vector<Attribute> outer_attribs = std::vector<Attribute> ()) : BaseLoopExpr (std::move (loop_body), locus, std::move (loop_label), std::move (outer_attribs)), @@ -3889,6 +3991,11 @@ public: return *pattern; } + BaseLoopExpr::Kind get_loop_kind () const override + { + return BaseLoopExpr::Kind::For; + } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -4012,6 +4119,8 @@ public: const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; } std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; } + Expr::Kind get_expr_kind () const override { return Expr::Kind::If; } + protected: // Base clone function but still concrete as concrete base class virtual IfExpr *clone_if_expr_impl () const { return new IfExpr (*this); } @@ -4206,6 +4315,8 @@ public: const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; } std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; } + Expr::Kind get_expr_kind () const override { return Expr::Kind::IfLet; } + protected: /* Use covariance to implement clone function as returning this object rather * than base (or rather this or any derived object) */ @@ -4535,6 +4646,8 @@ public: const std::vector<MatchCase> &get_match_cases () const { return match_arms; } std::vector<MatchCase> &get_match_cases () { return match_arms; } + Expr::Kind get_expr_kind () const override { return Expr::Kind::Match; } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -4614,6 +4727,8 @@ public: outer_attrs = std::move (new_attrs); } + Expr::Kind get_expr_kind () const override { return Expr::Kind::Await; } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -4696,6 +4811,8 @@ public: outer_attrs = std::move (new_attrs); } + Expr::Kind get_expr_kind () const override { return Expr::Kind::AsyncBlock; } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -4768,9 +4885,31 @@ struct InlineAsmRegOrRegClass location_t locus; }; -struct InlineAsmOperand +struct LlvmOperand { - enum RegisterType + std::string constraint; + std::unique_ptr<Expr> expr; + + LlvmOperand (std::string constraint, std::unique_ptr<Expr> &&expr) + : constraint (constraint), expr (std::move (expr)) + {} + + LlvmOperand (const LlvmOperand &other) + : constraint (other.constraint), expr (other.expr->clone_expr ()) + {} + LlvmOperand &operator= (const LlvmOperand &other) + { + constraint = other.constraint; + expr = other.expr->clone_expr (); + + return *this; + } +}; + +class InlineAsmOperand +{ +public: + enum class RegisterType { In, Out, @@ -4781,8 +4920,24 @@ struct InlineAsmOperand Label, }; - struct In + class Register + { + public: + Register () {} + virtual ~Register () = default; + + std::unique_ptr<Register> clone () const + { + return std::unique_ptr<Register> (clone_impl ()); + } + + protected: + virtual Register *clone_impl () const = 0; + }; + + class In : public Register { + public: tl::optional<InlineAsmRegOrRegClass> reg; std::unique_ptr<Expr> expr; @@ -4793,24 +4948,28 @@ struct InlineAsmOperand rust_assert (this->expr != nullptr); } - In (const struct In &other) + In (const In &other) { reg = other.reg; expr = other.expr->clone_expr (); } - In operator= (const struct In &other) + In operator= (const In &other) { reg = other.reg; expr = other.expr->clone_expr (); return *this; } + + private: + In *clone_impl () const { return new In (*this); } }; - struct Out + class Out : public Register { + public: tl::optional<InlineAsmRegOrRegClass> reg; bool late; std::unique_ptr<Expr> expr; // can be null @@ -4822,24 +4981,28 @@ struct InlineAsmOperand rust_assert (this->expr != nullptr); } - Out (const struct Out &other) + Out (const Out &other) { reg = other.reg; late = other.late; expr = other.expr->clone_expr (); } - Out operator= (const struct Out &other) + Out operator= (const Out &other) { reg = other.reg; late = other.late; expr = other.expr->clone_expr (); return *this; } + + private: + Out *clone_impl () const { return new Out (*this); } }; - struct InOut + class InOut : public Register { + public: tl::optional<InlineAsmRegOrRegClass> reg; bool late; std::unique_ptr<Expr> expr; // this can't be null @@ -4851,14 +5014,14 @@ struct InlineAsmOperand rust_assert (this->expr != nullptr); } - InOut (const struct InOut &other) + InOut (const InOut &other) { reg = other.reg; late = other.late; expr = other.expr->clone_expr (); } - InOut operator= (const struct InOut &other) + InOut operator= (const InOut &other) { reg = other.reg; late = other.late; @@ -4866,10 +5029,14 @@ struct InlineAsmOperand return *this; } + + private: + InOut *clone_impl () const { return new InOut (*this); } }; - struct SplitInOut + class SplitInOut : public Register { + public: tl::optional<InlineAsmRegOrRegClass> reg; bool late; std::unique_ptr<Expr> in_expr; @@ -4884,7 +5051,7 @@ struct InlineAsmOperand rust_assert (this->out_expr != nullptr); } - SplitInOut (const struct SplitInOut &other) + SplitInOut (const SplitInOut &other) { reg = other.reg; late = other.late; @@ -4892,7 +5059,7 @@ struct InlineAsmOperand out_expr = other.out_expr->clone_expr (); } - SplitInOut operator= (const struct SplitInOut &other) + SplitInOut operator= (const SplitInOut &other) { reg = other.reg; late = other.late; @@ -4901,35 +5068,47 @@ struct InlineAsmOperand return *this; } + + private: + SplitInOut *clone_impl () const { return new SplitInOut (*this); } }; - struct Const + class Const : public Register { + public: AnonConst anon_const; + + private: + Const *clone_impl () const { return new Const (*this); } }; - struct Sym + class Sym : public Register { + public: std::unique_ptr<Expr> expr; Sym (std::unique_ptr<Expr> expr) : expr (std::move (expr)) { rust_assert (this->expr != nullptr); } - Sym (const struct Sym &other) + Sym (const Sym &other) { expr = std::unique_ptr<Expr> (other.expr->clone_expr ()); } - Sym operator= (const struct Sym &other) + Sym operator= (const Sym &other) { expr = std::unique_ptr<Expr> (other.expr->clone_expr ()); return *this; } + + private: + Sym *clone_impl () const { return new Sym (*this); } }; - struct Label + class Label : public Register { + public: std::string label_name; std::unique_ptr<Expr> expr; @@ -4940,86 +5119,137 @@ struct InlineAsmOperand if (label_name.has_value ()) this->label_name = label_name.value (); } - Label (const struct Label &other) + Label (const Label &other) { expr = std::unique_ptr<Expr> (other.expr->clone_expr ()); } - Label operator= (const struct Label &other) + Label operator= (const Label &other) { expr = std::unique_ptr<Expr> (other.expr->clone_expr ()); return *this; } - }; - RegisterType register_type; - - tl::optional<struct In> in; - tl::optional<struct Out> out; - tl::optional<struct InOut> in_out; - tl::optional<struct SplitInOut> split_in_out; - tl::optional<struct Const> cnst; - tl::optional<struct Sym> sym; - tl::optional<struct Label> label; + private: + Label *clone_impl () const { return new Label (*this); } + }; - InlineAsmOperand () {} InlineAsmOperand (const InlineAsmOperand &other) - : in (other.in), out (other.out), in_out (other.in_out), - split_in_out (other.split_in_out), cnst (other.cnst), sym (other.sym) + : register_type (other.register_type), locus (other.locus), + reg (other.reg->clone ()) {} - void set_in (const tl::optional<struct In> ®) - { - this->register_type = In; + InlineAsmOperand (const In ®, location_t locus) + : register_type (RegisterType::In), locus (locus), reg (new In (reg)) + {} + InlineAsmOperand (const Out ®, location_t locus) + : register_type (RegisterType::Out), locus (locus), reg (new Out (reg)) + {} + InlineAsmOperand (const InOut ®, location_t locus) + : register_type (RegisterType::InOut), locus (locus), reg (new InOut (reg)) + {} + InlineAsmOperand (const SplitInOut ®, location_t locus) + : register_type (RegisterType::SplitInOut), locus (locus), + reg (new SplitInOut (reg)) + {} + InlineAsmOperand (const Const ®, location_t locus) + : register_type (RegisterType::Const), locus (locus), reg (new Const (reg)) + {} + InlineAsmOperand (const Sym ®, location_t locus) + : register_type (RegisterType::Sym), locus (locus), reg (new Sym (reg)) + {} + InlineAsmOperand (const Label ®, location_t locus) + : register_type (RegisterType::Label), locus (locus), reg (new Label (reg)) + {} - if (reg.has_value ()) - this->in = reg.value (); - } + location_t get_locus () const { return locus; } + RegisterType get_register_type () const { return register_type; } - void set_out (const tl::optional<struct Out> ®) + // Potentially fail immediately if you don't use get_register_type() to + // inspect the RegisterType first before calling the following functions Check + // first + In &get_in () + { + rust_assert (register_type == RegisterType::In); + return static_cast<In &> (*reg); + } + const In &get_in () const { - this->register_type = Out; + rust_assert (register_type == RegisterType::In); + return static_cast<const In &> (*reg); + } - if (reg.has_value ()) - this->out = reg.value (); + Out &get_out () + { + rust_assert (register_type == RegisterType::Out); + return static_cast<Out &> (*reg); + } + const Out &get_out () const + { + rust_assert (register_type == RegisterType::Out); + return static_cast<const Out &> (*reg); } - void set_in_out (const tl::optional<struct InOut> ®) + InOut &get_in_out () { - this->register_type = InOut; - if (reg.has_value ()) - this->in_out = reg.value (); + rust_assert (register_type == RegisterType::InOut); + return static_cast<InOut &> (*reg); + } + const InOut &get_in_out () const + { + rust_assert (register_type == RegisterType::InOut); + return static_cast<const InOut &> (*reg); } - void set_split_in_out (const tl::optional<struct SplitInOut> ®) + SplitInOut &get_split_in_out () { - this->register_type = SplitInOut; - if (reg.has_value ()) - this->split_in_out = reg.value (); + rust_assert (register_type == RegisterType::SplitInOut); + return static_cast<SplitInOut &> (*reg); + } + const SplitInOut &get_split_in_out () const + { + rust_assert (register_type == RegisterType::SplitInOut); + return static_cast<const SplitInOut &> (*reg); } - void set_cnst (const tl::optional<struct Const> ®) + Const &get_const () + { + rust_assert (register_type == RegisterType::Const); + return static_cast<Const &> (*reg); + } + const Const &get_const () const { - this->register_type = Const; - if (reg.has_value ()) - this->cnst = reg.value (); + rust_assert (register_type == RegisterType::Const); + return static_cast<Const &> (*reg); } - void set_sym (const tl::optional<struct Sym> ®) + Sym &get_sym () + { + rust_assert (register_type == RegisterType::Sym); + return static_cast<Sym &> (*reg); + } + const Sym &get_sym () const { - this->register_type = Sym; - if (reg.has_value ()) - this->sym = reg.value (); + rust_assert (register_type == RegisterType::Sym); + return static_cast<const Sym &> (*reg); } - void set_label (const tl::optional<struct Label> ®) + Label &get_label () { - this->register_type = Label; - if (reg.has_value ()) - this->label = reg.value (); + rust_assert (register_type == RegisterType::Label); + return static_cast<Label &> (*reg); } + const Label &get_label () const + { + rust_assert (register_type == RegisterType::Label); + return static_cast<const Label &> (*reg); + } + +private: + RegisterType register_type; location_t locus; + std::unique_ptr<Register> reg; }; struct InlineAsmPlaceHolder @@ -5049,6 +5279,7 @@ struct TupleTemplateStr location_t loc; std::string symbol; + location_t get_locus () { return loc; } TupleTemplateStr (location_t loc, const std::string &symbol) : loc (loc), symbol (symbol) {} @@ -5117,6 +5348,79 @@ public: { return new InlineAsm (*this); } + + Expr::Kind get_expr_kind () const override { return Expr::Kind::InlineAsm; } +}; + +class LlvmInlineAsm : public ExprWithoutBlock +{ + // llvm_asm!("" : : "r"(&mut dummy) : "memory" : "volatile"); + // Asm, Outputs, Inputs, Clobbers, Options, + +public: + enum class Dialect + { + Att, + Intel, + }; + +private: + location_t locus; + std::vector<Attribute> outer_attrs; + std::vector<LlvmOperand> inputs; + std::vector<LlvmOperand> outputs; + std::vector<TupleTemplateStr> templates; + std::vector<TupleClobber> clobbers; + bool volatility; + bool align_stack; + Dialect dialect; + +public: + LlvmInlineAsm (location_t locus) : locus (locus) {} + + Dialect get_dialect () { return dialect; } + + location_t get_locus () const override { return locus; } + + void mark_for_strip () override {} + + bool is_marked_for_strip () const override { return false; } + + std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; } + + void accept_vis (ASTVisitor &vis) override; + + std::string as_string () const override { return "InlineAsm AST Node"; } + + void set_outer_attrs (std::vector<Attribute> v) override { outer_attrs = v; } + + LlvmInlineAsm *clone_expr_without_block_impl () const override + { + return new LlvmInlineAsm (*this); + } + + std::vector<TupleTemplateStr> &get_templates () { return templates; } + + Expr::Kind get_expr_kind () const override + { + return Expr::Kind::LlvmInlineAsm; + } + + void set_align_stack (bool align_stack) { this->align_stack = align_stack; } + bool is_stack_aligned () { return align_stack; } + + void set_volatile (bool volatility) { this->volatility = volatility; } + bool is_volatile () { return volatility; } + + void set_dialect (Dialect dialect) { this->dialect = dialect; } + + void set_inputs (std::vector<LlvmOperand> operands) { inputs = operands; } + void set_outputs (std::vector<LlvmOperand> operands) { outputs = operands; } + + std::vector<LlvmOperand> &get_inputs () { return inputs; } + std::vector<LlvmOperand> &get_outputs () { return outputs; } + + std::vector<TupleClobber> &get_clobbers () { return clobbers; } }; } // namespace AST diff --git a/gcc/rust/ast/rust-item.h b/gcc/rust/ast/rust-item.h index bd9113f..062f85d 100644 --- a/gcc/rust/ast/rust-item.h +++ b/gcc/rust/ast/rust-item.h @@ -434,13 +434,14 @@ class SelfParam : public Param bool has_ref; bool is_mut; // bool has_lifetime; // only possible if also ref - Lifetime lifetime; + tl::optional<Lifetime> lifetime; // bool has_type; // only possible if not ref std::unique_ptr<Type> type; // Unrestricted constructor used for error state - SelfParam (Lifetime lifetime, bool has_ref, bool is_mut, Type *type) + SelfParam (tl::optional<Lifetime> lifetime, bool has_ref, bool is_mut, + Type *type) : Param ({}, UNDEF_LOCATION), has_ref (has_ref), is_mut (is_mut), lifetime (std::move (lifetime)), type (type) {} @@ -453,7 +454,7 @@ public: bool has_type () const { return type != nullptr; } // Returns whether the self-param has a valid lifetime. - bool has_lifetime () const { return !lifetime.is_error (); } + bool has_lifetime () const { return lifetime.has_value (); } // Returns whether the self-param is in an error state. bool is_error () const @@ -472,11 +473,11 @@ public: // Type-based self parameter (not ref, no lifetime) SelfParam (std::unique_ptr<Type> type, bool is_mut, location_t locus) : Param ({}, locus), has_ref (false), is_mut (is_mut), - lifetime (Lifetime::error ()), type (std::move (type)) + lifetime (tl::nullopt), type (std::move (type)) {} // Lifetime-based self parameter (is ref, no type) - SelfParam (Lifetime lifetime, bool is_mut, location_t locus) + SelfParam (tl::optional<Lifetime> lifetime, bool is_mut, location_t locus) : Param ({}, locus), has_ref (true), is_mut (is_mut), lifetime (std::move (lifetime)) {} @@ -522,8 +523,8 @@ public: bool get_has_ref () const { return has_ref; }; bool get_is_mut () const { return is_mut; } - Lifetime get_lifetime () const { return lifetime; } - Lifetime &get_lifetime () { return lifetime; } + Lifetime get_lifetime () const { return lifetime.value (); } + Lifetime &get_lifetime () { return lifetime.value (); } NodeId get_node_id () const { return node_id; } @@ -758,8 +759,6 @@ public: Identifier get_name () const { return module_name; } - AST::Kind get_ast_kind () const override { return AST::Kind::MODULE; } - private: Identifier module_name; location_t locus; @@ -899,6 +898,8 @@ public: void mark_for_strip () override { module_name = {""}; } bool is_marked_for_strip () const override { return module_name.empty (); } + Item::Kind get_item_kind () const override { return Item::Kind::Module; } + protected: /* Use covariance to implement clone function as returning this object * rather than base */ @@ -960,6 +961,8 @@ public: return referenced_crate.empty (); } + Item::Kind get_item_kind () const override { return Item::Kind::ExternCrate; } + protected: /* Use covariance to implement clone function as returning this object * rather than base */ @@ -1213,7 +1216,7 @@ public: std::string as_string () const override; - NewBindType get_new_bind_type () { return bind_type; } + NewBindType get_new_bind_type () const { return bind_type; } void accept_vis (ASTVisitor &vis) override; @@ -1301,6 +1304,11 @@ public: void mark_for_strip () override { use_tree = nullptr; } bool is_marked_for_strip () const override { return use_tree == nullptr; } + Item::Kind get_item_kind () const override + { + return Item::Kind::UseDeclaration; + } + protected: /* Use covariance to implement clone function as returning this object * rather than base */ @@ -1323,7 +1331,7 @@ class Function : public VisItem, public AssociatedItem, public ExternalItem WhereClause where_clause; tl::optional<std::unique_ptr<BlockExpr>> function_body; location_t locus; - bool is_default; + bool has_default; bool is_external_function; public: @@ -1348,6 +1356,8 @@ public: bool has_body () const { return function_body.has_value (); } + bool is_default () const { return has_default; } + // Mega-constructor with all possible fields Function (Identifier function_name, FunctionQualifiers qualifiers, std::vector<std::unique_ptr<GenericParam>> generic_params, @@ -1355,7 +1365,7 @@ public: std::unique_ptr<Type> return_type, WhereClause where_clause, tl::optional<std::unique_ptr<BlockExpr>> function_body, Visibility vis, std::vector<Attribute> outer_attrs, - location_t locus, bool is_default = false, + location_t locus, bool has_default = false, bool is_external_function = false) : VisItem (std::move (vis), std::move (outer_attrs)), ExternalItem (Stmt::node_id), qualifiers (std::move (qualifiers)), @@ -1365,7 +1375,7 @@ public: return_type (std::move (return_type)), where_clause (std::move (where_clause)), function_body (std::move (function_body)), locus (locus), - is_default (is_default), is_external_function (is_external_function) + has_default (has_default), is_external_function (is_external_function) {} // TODO: add constructor with less fields @@ -1459,6 +1469,8 @@ public: // ExternalItem::node_id is same as Stmt::node_id NodeId get_node_id () const override { return Stmt::node_id; } + Item::Kind get_item_kind () const override { return Item::Kind::Function; } + protected: /* Use covariance to implement clone function as returning this object * rather than base */ @@ -1590,6 +1602,8 @@ public: Identifier get_new_type_name () const { return new_type_name; } + Item::Kind get_item_kind () const override { return Item::Kind::TypeAlias; } + protected: /* Use covariance to implement clone function as returning this object * rather than base */ @@ -1649,6 +1663,8 @@ public: Identifier get_identifier () const { return struct_name; } + Item::Kind get_item_kind () const override { return Item::Kind::Struct; } + protected: Struct (Identifier struct_name, std::vector<std::unique_ptr<GenericParam>> generic_params, @@ -1994,6 +2010,41 @@ class EnumItem : public VisItem location_t locus; public: + enum class Kind + { + Identifier, + Tuple, + Struct, + + // FIXME: In the future, we'll need to remove this possibility as well as + // remove the EnumItemDiscriminant class. The feature for arbitrary + // discriminants on all kinds of variants has been stabilized, and a + // "discriminant" is no longer an enum item variant - it's simply an + // optional part of all variants. + // + // Per the reference: + // + // EnumItem : + // OuterAttribute* Visibility? + // IDENTIFIER ( EnumItemTuple | EnumItemStruct )? EnumItemDiscriminant? + // + // EnumItemTuple : + // ( TupleFields? ) + // + // EnumItemStruct : + // { StructFields? } + // + // EnumItemDiscriminant : + // = Expression + // + // So we instead need to remove the class, and add an optional expression to + // the base EnumItem class + // + // gccrs#3340 + + Discriminant, + }; + virtual ~EnumItem () {} EnumItem (Identifier variant_name, Visibility vis, @@ -2002,6 +2053,8 @@ public: variant_name (std::move (variant_name)), locus (locus) {} + virtual Kind get_enum_item_kind () const { return Kind::Identifier; } + // Unique pointer custom clone function std::unique_ptr<EnumItem> clone_enum_item () const { @@ -2021,6 +2074,8 @@ public: void mark_for_strip () override { variant_name = {""}; } bool is_marked_for_strip () const override { return variant_name.empty (); } + Item::Kind get_item_kind () const override { return Item::Kind::EnumItem; } + protected: EnumItem *clone_item_impl () const override { return new EnumItem (*this); } }; @@ -2043,6 +2098,11 @@ public: tuple_fields (std::move (tuple_fields)) {} + EnumItem::Kind get_enum_item_kind () const override + { + return EnumItem::Kind::Tuple; + } + std::string as_string () const override; void accept_vis (ASTVisitor &vis) override; @@ -2080,6 +2140,11 @@ public: struct_fields (std::move (struct_fields)) {} + EnumItem::Kind get_enum_item_kind () const override + { + return EnumItem::Kind::Struct; + } + std::string as_string () const override; void accept_vis (ASTVisitor &vis) override; @@ -2133,6 +2198,11 @@ public: EnumItemDiscriminant (EnumItemDiscriminant &&other) = default; EnumItemDiscriminant &operator= (EnumItemDiscriminant &&other) = default; + EnumItem::Kind get_enum_item_kind () const override + { + return EnumItem::Kind::Discriminant; + } + std::string as_string () const override; void accept_vis (ASTVisitor &vis) override; @@ -2269,6 +2339,8 @@ public: // TODO: is this better? Or is a "vis_block" better? WhereClause &get_where_clause () { return where_clause; } + Item::Kind get_item_kind () const override { return Item::Kind::Enum; } + protected: /* Use covariance to implement clone function as returning this object * rather than base */ @@ -2368,6 +2440,8 @@ public: Identifier get_identifier () const { return union_name; } + Item::Kind get_item_kind () const override { return Item::Kind::Union; } + protected: /* Use covariance to implement clone function as returning this object * rather than base */ @@ -2489,6 +2563,11 @@ public: std::string get_identifier () const { return identifier; } + Item::Kind get_item_kind () const override + { + return Item::Kind::ConstantItem; + } + protected: /* Use covariance to implement clone function as returning this object * rather than base */ @@ -2610,6 +2689,8 @@ public: Identifier get_identifier () const { return name; } + Item::Kind get_item_kind () const override { return Item::Kind::StaticItem; } + protected: /* Use covariance to implement clone function as returning this object * rather than base */ @@ -2831,6 +2912,7 @@ class Trait : public VisItem bool has_auto; Identifier name; std::vector<std::unique_ptr<GenericParam>> generic_params; + TypeParam self_param; std::vector<std::unique_ptr<TypeParamBound>> type_param_bounds; WhereClause where_clause; std::vector<Attribute> inner_attrs; @@ -2870,7 +2952,7 @@ public: std::vector<Attribute> inner_attrs, location_t locus) : VisItem (std::move (vis), std::move (outer_attrs)), has_unsafe (is_unsafe), has_auto (is_auto), name (std::move (name)), - generic_params (std::move (generic_params)), + generic_params (std::move (generic_params)), self_param ({"Self"}, locus), type_param_bounds (std::move (type_param_bounds)), where_clause (std::move (where_clause)), inner_attrs (std::move (inner_attrs)), @@ -2880,8 +2962,9 @@ public: // Copy constructor with vector clone Trait (Trait const &other) : VisItem (other), has_unsafe (other.has_unsafe), has_auto (other.has_auto), - name (other.name), where_clause (other.where_clause), - inner_attrs (other.inner_attrs), locus (other.locus) + name (other.name), self_param (other.self_param), + where_clause (other.where_clause), inner_attrs (other.inner_attrs), + locus (other.locus) { generic_params.reserve (other.generic_params.size ()); for (const auto &e : other.generic_params) @@ -2901,6 +2984,7 @@ public: { VisItem::operator= (other); name = other.name; + self_param = other.self_param; has_unsafe = other.has_unsafe; has_auto = other.has_auto; where_clause = other.where_clause; @@ -2968,19 +3052,9 @@ public: WhereClause &get_where_clause () { return where_clause; } - void insert_implict_self (std::unique_ptr<AST::GenericParam> &¶m) - { - std::vector<std::unique_ptr<GenericParam>> new_list; - new_list.reserve (generic_params.size () + 1); - - new_list.push_back (std::move (param)); - for (auto &p : generic_params) - { - new_list.push_back (std::move (p)); - } + AST::TypeParam &get_implicit_self () { return self_param; } - generic_params = std::move (new_list); - } + Item::Kind get_item_kind () const override { return Item::Kind::Trait; } protected: /* Use covariance to implement clone function as returning this object @@ -3054,6 +3128,8 @@ public: return trait_type; } + Item::Kind get_item_kind () const override { return Item::Kind::Impl; } + protected: // Mega-constructor Impl (std::vector<std::unique_ptr<GenericParam>> generic_params, @@ -3202,8 +3278,8 @@ public: : Impl (std::move (generic_params), std::move (trait_type), std::move (where_clause), std::move (vis), std::move (inner_attrs), std::move (outer_attrs), locus), - has_unsafe (is_unsafe), has_exclam (has_exclam), - trait_path (std::move (trait_path)), impl_items (std::move (impl_items)) + has_unsafe (is_unsafe), has_exclam (has_exclam), trait_path (trait_path), + impl_items (std::move (impl_items)) {} // Copy constructor with vector clone @@ -3251,11 +3327,7 @@ public: } // TODO: is this better? Or is a "vis_block" better? - TypePath &get_trait_path () - { - // TODO: assert that trait path is not empty? - return trait_path; - } + TypePath &get_trait_path () { return trait_path; } protected: /* Use covariance to implement clone function as returning this object @@ -3528,303 +3600,6 @@ protected: } }; -// A named function parameter used in external functions -class NamedFunctionParam -{ - // bool has_name; // otherwise is _ - std::string name; - - std::unique_ptr<Type> param_type; - - // seemingly new since writing this node - std::vector<Attribute> outer_attrs; - - NodeId node_id; - location_t locus; - bool variadic; - -public: - /* Returns whether the named function parameter has a name (i.e. name is not - * '_'). */ - bool has_name () const { return name != "_" && name != ""; } - - bool has_outer_attrs () const { return !outer_attrs.empty (); } - - // Returns whether the named function parameter is in an error state. - bool is_error () const - { - // also if identifier is "" but that is probably more costly to compute - return param_type == nullptr && !variadic; - } - - bool is_variadic () const { return variadic; } - - std::string get_name () const { return name; } - - location_t get_locus () { return locus; } - - // Creates an error state named function parameter. - static NamedFunctionParam create_error () - { - return NamedFunctionParam ("", nullptr, {}, UNDEF_LOCATION); - } - - NamedFunctionParam (std::string name, std::unique_ptr<Type> param_type, - std::vector<Attribute> outer_attrs, location_t locus) - : name (std::move (name)), param_type (std::move (param_type)), - outer_attrs (std::move (outer_attrs)), - node_id (Analysis::Mappings::get ().get_next_node_id ()), locus (locus), - variadic (false) - {} - - NamedFunctionParam (std::string name, std::vector<Attribute> outer_attrs, - location_t locus) - : name (std::move (name)), param_type (nullptr), - outer_attrs (std::move (outer_attrs)), - node_id (Analysis::Mappings::get ().get_next_node_id ()), locus (locus), - variadic (true) - {} - - NamedFunctionParam (std::vector<Attribute> outer_attrs, location_t locus) - : name (""), param_type (nullptr), outer_attrs (std::move (outer_attrs)), - node_id (Analysis::Mappings::get ().get_next_node_id ()), locus (locus), - variadic (true) - {} - - // Copy constructor - NamedFunctionParam (NamedFunctionParam const &other) - : name (other.name), outer_attrs (other.outer_attrs), - variadic (other.variadic) - { - node_id = other.node_id; - // guard to prevent null dereference (only required if error state) - if (other.param_type != nullptr) - param_type = other.param_type->clone_type (); - else - param_type = nullptr; - } - - ~NamedFunctionParam () = default; - - // Overloaded assignment operator to clone - NamedFunctionParam &operator= (NamedFunctionParam const &other) - { - node_id = other.node_id; - name = other.name; - // has_name = other.has_name; - outer_attrs = other.outer_attrs; - - // guard to prevent null dereference (only required if error state) - if (other.param_type != nullptr) - param_type = other.param_type->clone_type (); - else - param_type = nullptr; - - return *this; - } - - // move constructors - NamedFunctionParam (NamedFunctionParam &&other) = default; - NamedFunctionParam &operator= (NamedFunctionParam &&other) = default; - - std::string as_string () const; - - // Based on idea that nane should never be empty. - void mark_for_strip () { param_type = nullptr; }; - bool is_marked_for_strip () const { return is_error (); }; - - // TODO: this mutable getter seems really dodgy. Think up better way. - std::vector<Attribute> &get_outer_attrs () { return outer_attrs; } - const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; } - - // TODO: is this better? Or is a "vis_block" better? - Type &get_type () - { - rust_assert (param_type != nullptr); - return *param_type; - } - - std::unique_ptr<Type> &get_type_ptr () - { - rust_assert (param_type != nullptr); - return param_type; - } - - NodeId get_node_id () const { return node_id; } -}; - -// A function item used in an extern block -class ExternalFunctionItem : public ExternalItem -{ - // bool has_outer_attrs; - std::vector<Attribute> outer_attrs; - - // bool has_visibility; - Visibility visibility; - - Identifier item_name; - location_t locus; - - // bool has_generics; - // Generics generic_params; - std::vector<std::unique_ptr<GenericParam>> generic_params; // inlined - - // bool has_return_type; - // FunctionReturnType return_type; - std::unique_ptr<Type> return_type; // inlined - - // bool has_where_clause; - WhereClause where_clause; - - std::vector<NamedFunctionParam> function_params; - -public: - // Returns whether item has generic parameters. - bool has_generics () const { return !generic_params.empty (); } - - // Returns whether item has a return type (otherwise void). - bool has_return_type () const { return return_type != nullptr; } - - // Returns whether item has a where clause. - bool has_where_clause () const { return !where_clause.is_empty (); } - - // Returns whether item has outer attributes. - bool has_outer_attrs () const { return !outer_attrs.empty (); } - - // Returns whether item has non-default visibility. - bool has_visibility () const { return !visibility.is_error (); } - - // Returns whether item has variadic parameters. - bool is_variadic () const - { - return function_params.size () != 0 - && function_params.back ().is_variadic (); - } - - location_t get_locus () const { return locus; } - - Visibility &get_visibility () { return visibility; } - const Visibility &get_visibility () const { return visibility; } - - ExternalFunctionItem ( - Identifier item_name, - std::vector<std::unique_ptr<GenericParam>> generic_params, - std::unique_ptr<Type> return_type, WhereClause where_clause, - std::vector<NamedFunctionParam> function_params, Visibility vis, - std::vector<Attribute> outer_attrs, location_t locus) - : ExternalItem (), outer_attrs (std::move (outer_attrs)), - visibility (std::move (vis)), item_name (std::move (item_name)), - locus (locus), generic_params (std::move (generic_params)), - return_type (std::move (return_type)), - where_clause (std::move (where_clause)), - function_params (std::move (function_params)) - { - // TODO: assert that if has variadic outer attrs, then has_variadics is - // true? - } - - // Copy constructor with clone - ExternalFunctionItem (ExternalFunctionItem const &other) - : ExternalItem (other.get_node_id ()), outer_attrs (other.outer_attrs), - visibility (other.visibility), item_name (other.item_name), - locus (other.locus), where_clause (other.where_clause), - function_params (other.function_params) - { - node_id = other.node_id; - // guard to prevent null pointer dereference - if (other.return_type != nullptr) - return_type = other.return_type->clone_type (); - - generic_params.reserve (other.generic_params.size ()); - for (const auto &e : other.generic_params) - generic_params.push_back (e->clone_generic_param ()); - } - - // Overloaded assignment operator with clone - ExternalFunctionItem &operator= (ExternalFunctionItem const &other) - { - outer_attrs = other.outer_attrs; - visibility = other.visibility; - item_name = other.item_name; - locus = other.locus; - where_clause = other.where_clause; - function_params = other.function_params; - node_id = other.node_id; - - // guard to prevent null pointer dereference - if (other.return_type != nullptr) - return_type = other.return_type->clone_type (); - else - return_type = nullptr; - - generic_params.reserve (other.generic_params.size ()); - for (const auto &e : other.generic_params) - generic_params.push_back (e->clone_generic_param ()); - - return *this; - } - - // move constructors - ExternalFunctionItem (ExternalFunctionItem &&other) = default; - ExternalFunctionItem &operator= (ExternalFunctionItem &&other) = default; - - std::string as_string () const override; - - void accept_vis (ASTVisitor &vis) override; - - // Based on idea that nane should never be empty. - void mark_for_strip () override { item_name = {""}; }; - bool is_marked_for_strip () const override { return item_name.empty (); }; - - // TODO: this mutable getter seems really dodgy. Think up better way. - std::vector<Attribute> &get_outer_attrs () { return outer_attrs; } - const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; } - - std::vector<NamedFunctionParam> &get_function_params () - { - return function_params; - } - const std::vector<NamedFunctionParam> &get_function_params () const - { - return function_params; - } - - std::vector<std::unique_ptr<GenericParam>> &get_generic_params () - { - return generic_params; - } - const std::vector<std::unique_ptr<GenericParam>> &get_generic_params () const - { - return generic_params; - } - - // TODO: is this better? Or is a "vis_block" better? - WhereClause &get_where_clause () { return where_clause; } - - // TODO: is this better? Or is a "vis_block" better? - Type &get_return_type () - { - rust_assert (has_return_type ()); - return *return_type; - } - - std::unique_ptr<Type> &get_return_type_ptr () - { - rust_assert (has_return_type ()); - return return_type; - } - - Identifier get_identifier () const { return item_name; }; - -protected: - /* Use covariance to implement clone function as returning this object - * rather than base */ - ExternalFunctionItem *clone_external_item_impl () const override - { - return new ExternalFunctionItem (*this); - } -}; - // An extern block AST node class ExternBlock : public VisItem { @@ -3917,6 +3692,8 @@ public: const std::vector<Attribute> &get_inner_attrs () const { return inner_attrs; } std::vector<Attribute> &get_inner_attrs () { return inner_attrs; } + Item::Kind get_item_kind () const override { return Item::Kind::ExternBlock; } + protected: /* Use covariance to implement clone function as returning this object * rather than base */ diff --git a/gcc/rust/ast/rust-macro.h b/gcc/rust/ast/rust-macro.h index 76b3b2a..fc01e57 100644 --- a/gcc/rust/ast/rust-macro.h +++ b/gcc/rust/ast/rust-macro.h @@ -24,11 +24,11 @@ #include "rust-ast-fragment.h" #include "rust-location.h" #include "rust-item.h" -#include "rust-make-unique.h" #include "rust-macro-builtins.h" namespace Rust { namespace AST { + class MacroFragSpec { public: @@ -521,7 +521,7 @@ public: mbe (Identifier rule_name, DelimType delim_type, std::vector<MacroRule> rules, std::vector<Attribute> outer_attrs, location_t locus) { - return Rust::make_unique<MacroRulesDefinition> ( + return std::make_unique<MacroRulesDefinition> ( MacroRulesDefinition (rule_name, delim_type, rules, outer_attrs, locus, AST::MacroRulesDefinition::MacroKind::MBE, AST::Visibility::create_error ())); @@ -532,7 +532,7 @@ public: std::vector<Attribute> outer_attrs, location_t locus, Visibility vis) { - return Rust::make_unique<MacroRulesDefinition> (MacroRulesDefinition ( + return std::make_unique<MacroRulesDefinition> (MacroRulesDefinition ( rule_name, AST::DelimType::CURLY, rules, outer_attrs, locus, AST::MacroRulesDefinition::MacroKind::DeclMacro, vis)); } @@ -572,13 +572,13 @@ public: is_builtin_rule = true; } - AST::Kind get_ast_kind () const override + MacroKind get_kind () const { return kind; } + + Item::Kind get_item_kind () const override { - return AST::Kind::MACRO_RULES_DEFINITION; + return Item::Kind::MacroRulesDefinition; } - MacroKind get_kind () const { return kind; } - protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -610,11 +610,6 @@ public: std::string as_string () const override; - Pattern::Kind get_pattern_kind () override - { - return Pattern::Kind::MacroInvocation; - } - /** * The default constructor you should use. Whenever we parse a macro call, we * cannot possibly know whether or not this call refers to a builtin macro or @@ -677,11 +672,6 @@ public: return ExprWithoutBlock::get_node_id (); } - AST::Kind get_ast_kind () const override - { - return AST::Kind::MACRO_INVOCATION; - } - NodeId get_macro_node_id () const { return node_id; } MacroInvocData &get_invoc_data () { return invoc_data; } @@ -800,6 +790,21 @@ public: void add_semicolon () override { is_semi_coloned = true; } + Pattern::Kind get_pattern_kind () override + { + return Pattern::Kind::MacroInvocation; + } + + Expr::Kind get_expr_kind () const override + { + return Expr::Kind::MacroInvocation; + } + + Item::Kind get_item_kind () const override + { + return Item::Kind::MacroInvocation; + } + protected: Item *clone_item_impl () const override { diff --git a/gcc/rust/ast/rust-path.cc b/gcc/rust/ast/rust-path.cc index 3aaf263..8e43ddf 100644 --- a/gcc/rust/ast/rust-path.cc +++ b/gcc/rust/ast/rust-path.cc @@ -17,6 +17,7 @@ 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-path.h" #include "rust-system.h" #include "rust-ast-full.h" #include "rust-diagnostics.h" @@ -118,7 +119,7 @@ ConstGenericParam::as_string () const str += "const " + name.as_string () + ": " + type->as_string (); if (has_default_value ()) - str += " = " + get_default_value ().as_string (); + str += " = " + get_default_value_unchecked ().as_string (); return str; } @@ -135,8 +136,11 @@ PathExprSegment::as_string () const } std::string -PathPattern::as_string () const +Path::as_string () const { + // FIXME: Impl for lang items + rust_assert (kind == Kind::Regular); + std::string str; for (const auto &segment : segments) @@ -149,8 +153,10 @@ PathPattern::as_string () const } SimplePath -PathPattern::convert_to_simple_path (bool with_opening_scope_resolution) const +Path::convert_to_simple_path (bool with_opening_scope_resolution) const { + rust_assert (kind == Kind::Regular); + if (!has_segments ()) return SimplePath::create_empty (); @@ -197,7 +203,7 @@ PathInExpression::as_string () const if (has_opening_scope_resolution) str = "::"; - return str + PathPattern::as_string (); + return str + Path::as_string (); } std::string @@ -297,7 +303,7 @@ TypePathFunction::as_string () const std::string QualifiedPathInExpression::as_string () const { - return path_type.as_string () + "::" + PathPattern::as_string (); + return path_type.as_string () + "::" + Path::as_string (); } std::string diff --git a/gcc/rust/ast/rust-path.h b/gcc/rust/ast/rust-path.h index b20f31c..a4ba93b 100644 --- a/gcc/rust/ast/rust-path.h +++ b/gcc/rust/ast/rust-path.h @@ -21,7 +21,11 @@ /* "Path" (identifier within namespaces, essentially) handling. Required include * for virtually all AST-related functionality. */ +#include "optional.h" #include "rust-ast.h" +#include "rust-hir-map.h" +#include "rust-mapping-common.h" +#include "rust-system.h" #include "system.h" namespace Rust { @@ -52,10 +56,16 @@ public: location_t get_locus () const { return locus; } - bool is_super_segment () const { return as_string ().compare ("super") == 0; } - bool is_crate_segment () const { return as_string ().compare ("crate") == 0; } - bool is_lower_self () const { return as_string ().compare ("self") == 0; } - bool is_big_self () const { return as_string ().compare ("Self") == 0; } + bool is_super_path_seg () const + { + return as_string ().compare ("super") == 0; + } + bool is_crate_path_seg () const + { + return as_string ().compare ("crate") == 0; + } + bool is_lower_self_seg () const { return as_string ().compare ("self") == 0; } + bool is_big_self_seg () const { return as_string ().compare ("Self") == 0; } }; // A binding of an identifier to a type used in generic arguments in paths @@ -157,17 +167,11 @@ public: */ enum class Kind { - Error, Const, // A const value Type, // A type argument (not discernable during parsing) Either, // Either a type or a const value, cleared up during resolving }; - static GenericArg create_error () - { - return GenericArg (nullptr, nullptr, {""}, Kind::Error, UNDEF_LOCATION); - } - static GenericArg create_const (std::unique_ptr<Expr> expression) { auto locus = expression->get_locus (); @@ -212,8 +216,6 @@ public: GenericArg (GenericArg &&other) = default; GenericArg &operator= (GenericArg &&other) = default; - bool is_error () const { return kind == Kind::Error; } - Kind get_kind () const { return kind; } location_t get_locus () const { return locus; } @@ -229,8 +231,6 @@ public: break; case Kind::Either: break; - case Kind::Error: - rust_unreachable (); } } @@ -273,8 +273,6 @@ public: { switch (get_kind ()) { - case Kind::Error: - rust_unreachable (); case Kind::Either: return "Ambiguous: " + path.as_string (); case Kind::Const: @@ -345,15 +343,15 @@ class ConstGenericParam : public GenericParam /** * Default value for the const generic parameter */ - GenericArg default_value; + tl::optional<GenericArg> default_value; AST::AttrVec outer_attrs; location_t locus; public: ConstGenericParam (Identifier name, std::unique_ptr<AST::Type> type, - GenericArg default_value, AST::AttrVec outer_attrs, - location_t locus) + tl::optional<GenericArg> default_value, + AST::AttrVec outer_attrs, location_t locus) : name (name), type (std::move (type)), default_value (std::move (default_value)), outer_attrs (outer_attrs), locus (locus) @@ -366,7 +364,7 @@ public: {} bool has_type () const { return type != nullptr; } - bool has_default_value () const { return !default_value.is_error (); } + bool has_default_value () const { return default_value.has_value (); } const Identifier &get_name () const { return name; } @@ -379,18 +377,18 @@ public: return *type; } - GenericArg &get_default_value () + GenericArg &get_default_value_unchecked () { rust_assert (has_default_value ()); - return default_value; + return default_value.value (); } - const GenericArg &get_default_value () const + const GenericArg &get_default_value_unchecked () const { rust_assert (has_default_value ()); - return default_value; + return default_value.value (); } std::string as_string () const override; @@ -476,15 +474,23 @@ public: std::string as_string () const; - // TODO: is this better? Or is a "vis_pattern" better? std::vector<GenericArg> &get_generic_args () { return generic_args; } - // TODO: is this better? Or is a "vis_pattern" better? std::vector<GenericArgsBinding> &get_binding_args () { return binding_args; } + const std::vector<GenericArgsBinding> &get_binding_args () const + { + return binding_args; + } + std::vector<Lifetime> &get_lifetime_args () { return lifetime_args; }; - location_t get_locus () { return locus; } + const std::vector<Lifetime> &get_lifetime_args () const + { + return lifetime_args; + }; + + location_t get_locus () const { return locus; } }; /* A segment of a path in expression, including an identifier aspect and maybe @@ -549,68 +555,102 @@ public: bool is_super_path_seg () const { - return !has_generic_args () && get_ident_segment ().is_super_segment (); + return !has_generic_args () && get_ident_segment ().is_super_path_seg (); } bool is_crate_path_seg () const { - return !has_generic_args () && get_ident_segment ().is_crate_segment (); + return !has_generic_args () && get_ident_segment ().is_crate_path_seg (); } bool is_lower_self_seg () const { - return !has_generic_args () && get_ident_segment ().is_lower_self (); + return !has_generic_args () && get_ident_segment ().is_lower_self_seg (); } }; // AST node representing a pattern that involves a "path" - abstract base // class -class PathPattern : public Pattern +class Path : public Pattern { - std::vector<PathExprSegment> segments; +public: + enum class Kind + { + LangItem, + Regular, + }; -protected: - PathPattern (std::vector<PathExprSegment> segments) - : segments (std::move (segments)) + Path (std::vector<PathExprSegment> segments) + : segments (std::move (segments)), lang_item (tl::nullopt), + kind (Kind::Regular) + {} + + Path (LangItem::Kind lang_item) + : segments ({}), lang_item (lang_item), kind (Kind::LangItem) {} // Returns whether path has segments. - bool has_segments () const { return !segments.empty (); } + bool has_segments () const + { + rust_assert (kind == Kind::Regular); + return !segments.empty (); + } /* Converts path segments to their equivalent SimplePath segments if * possible, and creates a SimplePath from them. */ SimplePath convert_to_simple_path (bool with_opening_scope_resolution) const; - // Removes all segments of the path. - void remove_all_segments () - { - segments.clear (); - segments.shrink_to_fit (); - } - -public: /* Returns whether the path is a single segment (excluding qualified path * initial as segment). */ - bool is_single_segment () const { return segments.size () == 1; } + bool is_single_segment () const + { + rust_assert (kind == Kind::Regular); + return segments.size () == 1; + } std::string as_string () const override; + bool is_lang_item () const { return kind == Kind::LangItem; } + // TODO: this seems kinda dodgy - std::vector<PathExprSegment> &get_segments () { return segments; } - const std::vector<PathExprSegment> &get_segments () const { return segments; } + std::vector<PathExprSegment> &get_segments () + { + rust_assert (kind == Kind::Regular); + return segments; + } + const std::vector<PathExprSegment> &get_segments () const + { + rust_assert (kind == Kind::Regular); + return segments; + } + + LangItem::Kind get_lang_item () const + { + rust_assert (kind == Kind::LangItem); + return *lang_item; + } Pattern::Kind get_pattern_kind () override { return Pattern::Kind::Path; } + Path::Kind get_path_kind () { return kind; } + +protected: + std::vector<PathExprSegment> segments; + tl::optional<LangItem::Kind> lang_item; + + Path::Kind kind; }; /* AST node representing a path-in-expression pattern (path that allows * generic arguments) */ -class PathInExpression : public PathPattern, public PathExpr +class PathInExpression : public Path, public ExprWithoutBlock { std::vector<Attribute> outer_attrs; bool has_opening_scope_resolution; location_t locus; NodeId _node_id; + bool marked_for_strip; + public: std::string as_string () const override; @@ -618,16 +658,25 @@ public: PathInExpression (std::vector<PathExprSegment> path_segments, std::vector<Attribute> outer_attrs, location_t locus, bool has_opening_scope_resolution = false) - : PathPattern (std::move (path_segments)), - outer_attrs (std::move (outer_attrs)), + : Path (std::move (path_segments)), outer_attrs (std::move (outer_attrs)), has_opening_scope_resolution (has_opening_scope_resolution), - locus (locus), _node_id (Analysis::Mappings::get ().get_next_node_id ()) + locus (locus), _node_id (Analysis::Mappings::get ().get_next_node_id ()), + marked_for_strip (false) + {} + + PathInExpression (LangItem::Kind lang_item, + std::vector<Attribute> outer_attrs, location_t locus) + : Path (lang_item), outer_attrs (std::move (outer_attrs)), + has_opening_scope_resolution (false), locus (locus), + _node_id (Analysis::Mappings::get ().get_next_node_id ()), + marked_for_strip (false) {} // Creates an error state path in expression. static PathInExpression create_error () { - return PathInExpression ({}, {}, UNDEF_LOCATION); + return PathInExpression (std::vector<PathExprSegment> (), {}, + UNDEF_LOCATION); } // Returns whether path in expression is in an error state. @@ -650,9 +699,8 @@ public: void accept_vis (ASTVisitor &vis) override; - // Invalid if path is empty (error state), so base stripping on that. - void mark_for_strip () override { remove_all_segments (); } - bool is_marked_for_strip () const override { return is_error (); } + void mark_for_strip () override { marked_for_strip = true; } + bool is_marked_for_strip () const override { return marked_for_strip; } bool opening_scope_resolution () const { @@ -669,14 +717,17 @@ public: outer_attrs = std::move (new_attrs); } - NodeId get_pattern_node_id () const { return get_node_id (); } - PathExprSegment &get_final_segment () { return get_segments ().back (); } const PathExprSegment &get_final_segment () const { return get_segments ().back (); } + Expr::Kind get_expr_kind () const override + { + return Expr::Kind::PathInExpression; + } + protected: /* Use covariance to implement clone function as returning this object * rather than base */ @@ -711,7 +762,8 @@ public: }; private: - PathIdentSegment ident_segment; + tl::optional<LangItem::Kind> lang_item; + tl::optional<PathIdentSegment> ident_segment; location_t locus; protected: @@ -741,21 +793,30 @@ public: TypePathSegment (PathIdentSegment ident_segment, bool has_separating_scope_resolution, location_t locus) - : ident_segment (std::move (ident_segment)), locus (locus), + : lang_item (tl::nullopt), ident_segment (std::move (ident_segment)), + locus (locus), has_separating_scope_resolution (has_separating_scope_resolution), node_id (Analysis::Mappings::get ().get_next_node_id ()) {} + TypePathSegment (LangItem::Kind lang_item, location_t locus) + : lang_item (lang_item), ident_segment (tl::nullopt), locus (locus), + has_separating_scope_resolution (false), + node_id (Analysis::Mappings::get ().get_next_node_id ()) + {} + TypePathSegment (std::string segment_name, bool has_separating_scope_resolution, location_t locus) - : ident_segment (PathIdentSegment (std::move (segment_name), locus)), + : lang_item (tl::nullopt), + ident_segment (PathIdentSegment (std::move (segment_name), locus)), locus (locus), has_separating_scope_resolution (has_separating_scope_resolution), node_id (Analysis::Mappings::get ().get_next_node_id ()) {} TypePathSegment (TypePathSegment const &other) - : ident_segment (other.ident_segment), locus (other.locus), + : lang_item (other.lang_item), ident_segment (other.ident_segment), + locus (other.locus), has_separating_scope_resolution (other.has_separating_scope_resolution), node_id (other.node_id) {} @@ -763,6 +824,7 @@ public: TypePathSegment &operator= (TypePathSegment const &other) { ident_segment = other.ident_segment; + lang_item = other.lang_item; locus = other.locus; has_separating_scope_resolution = other.has_separating_scope_resolution; node_id = other.node_id; @@ -773,16 +835,28 @@ public: TypePathSegment (TypePathSegment &&other) = default; TypePathSegment &operator= (TypePathSegment &&other) = default; - virtual std::string as_string () const { return ident_segment.as_string (); } + virtual std::string as_string () const + { + if (lang_item.has_value ()) + return LangItem::PrettyString (*lang_item); + + return ident_segment->as_string (); + } /* Returns whether the type path segment is in an error state. May be * virtual in future. */ - bool is_error () const { return ident_segment.is_error (); } + bool is_error () const + { + rust_assert (ident_segment); + return ident_segment->is_error (); + } /* Returns whether segment is identifier only (as opposed to generic args or * function). Overridden in derived classes with other segments. */ virtual bool is_ident_only () const { return true; } + bool is_lang_item () const { return lang_item.has_value (); } + location_t get_locus () const { return locus; } // not pure virtual as class not abstract @@ -793,23 +867,41 @@ public: return has_separating_scope_resolution; } - PathIdentSegment &get_ident_segment () { return ident_segment; }; - const PathIdentSegment &get_ident_segment () const { return ident_segment; }; + PathIdentSegment &get_ident_segment () + { + rust_assert (!is_lang_item ()); + return *ident_segment; + }; + + const PathIdentSegment &get_ident_segment () const + { + rust_assert (!is_lang_item ()); + return *ident_segment; + }; + + LangItem::Kind get_lang_item () const + { + rust_assert (is_lang_item ()); + return *lang_item; + } NodeId get_node_id () const { return node_id; } bool is_crate_path_seg () const { - return get_ident_segment ().is_crate_segment (); + return get_ident_segment ().is_crate_path_seg (); } bool is_super_path_seg () const { - return get_ident_segment ().is_super_segment (); + return get_ident_segment ().is_super_path_seg (); + } + bool is_big_self_seg () const + { + return get_ident_segment ().is_big_self_seg (); } - bool is_big_self_seg () const { return get_ident_segment ().is_big_self (); } bool is_lower_self_seg () const { - return get_ident_segment ().is_lower_self (); + return get_ident_segment ().is_lower_self_seg (); } }; @@ -834,6 +926,12 @@ public: generic_args (std::move (generic_args)) {} + TypePathSegmentGeneric (LangItem::Kind lang_item, GenericArgs generic_args, + location_t locus) + : TypePathSegment (lang_item, locus), + generic_args (std::move (generic_args)) + {} + // Constructor from segment name and all args TypePathSegmentGeneric (std::string segment_name, bool has_separating_scope_resolution, @@ -891,7 +989,7 @@ private: /*bool has_inputs; TypePathFnInputs inputs;*/ // inlined from TypePathFnInputs - std::vector<std::unique_ptr<Type> > inputs; + std::vector<std::unique_ptr<Type>> inputs; // bool has_type; std::unique_ptr<Type> return_type; @@ -924,8 +1022,8 @@ public: } // Constructor - TypePathFunction (std::vector<std::unique_ptr<Type> > inputs, - location_t locus, std::unique_ptr<Type> type = nullptr) + TypePathFunction (std::vector<std::unique_ptr<Type>> inputs, location_t locus, + std::unique_ptr<Type> type = nullptr) : inputs (std::move (inputs)), return_type (std::move (type)), is_invalid (false), locus (locus) {} @@ -970,11 +1068,11 @@ public: std::string as_string () const; // TODO: this mutable getter seems really dodgy. Think up better way. - const std::vector<std::unique_ptr<Type> > &get_params () const + const std::vector<std::unique_ptr<Type>> &get_params () const { return inputs; } - std::vector<std::unique_ptr<Type> > &get_params () { return inputs; } + std::vector<std::unique_ptr<Type>> &get_params () { return inputs; } // TODO: is this better? Or is a "vis_pattern" better? Type &get_return_type () @@ -1038,11 +1136,10 @@ public: } }; -// Path used inside types class TypePath : public TypeNoBounds { bool has_opening_scope_resolution; - std::vector<std::unique_ptr<TypePathSegment> > segments; + std::vector<std::unique_ptr<TypePathSegment>> segments; location_t locus; protected: @@ -1067,12 +1164,20 @@ public: // Creates an error state TypePath. static TypePath create_error () { - return TypePath (std::vector<std::unique_ptr<TypePathSegment> > (), + return TypePath (std::vector<std::unique_ptr<TypePathSegment>> (), UNDEF_LOCATION); } // Constructor - TypePath (std::vector<std::unique_ptr<TypePathSegment> > segments, + TypePath (std::vector<std::unique_ptr<TypePathSegment>> segments, + location_t locus, bool has_opening_scope_resolution = false) + : TypeNoBounds (), + has_opening_scope_resolution (has_opening_scope_resolution), + segments (std::move (segments)), locus (locus) + {} + + TypePath (LangItem::Kind lang_item, + std::vector<std::unique_ptr<TypePathSegment>> segments, location_t locus, bool has_opening_scope_resolution = false) : TypeNoBounds (), has_opening_scope_resolution (has_opening_scope_resolution), @@ -1118,15 +1223,19 @@ public: TraitBound *to_trait_bound (bool in_parens) const override; location_t get_locus () const override final { return locus; } + NodeId get_node_id () const { return node_id; } + + void mark_for_strip () override {} + bool is_marked_for_strip () const override { return false; } void accept_vis (ASTVisitor &vis) override; // TODO: this seems kinda dodgy - std::vector<std::unique_ptr<TypePathSegment> > &get_segments () + std::vector<std::unique_ptr<TypePathSegment>> &get_segments () { return segments; } - const std::vector<std::unique_ptr<TypePathSegment> > &get_segments () const + const std::vector<std::unique_ptr<TypePathSegment>> &get_segments () const { return segments; } @@ -1147,9 +1256,8 @@ public: QualifiedPathType (std::unique_ptr<Type> invoke_on_type, location_t locus = UNDEF_LOCATION, TypePath trait_path = TypePath::create_error ()) - : type_to_invoke_on (std::move (invoke_on_type)), - trait_path (std::move (trait_path)), locus (locus), - node_id (Analysis::Mappings::get ().get_next_node_id ()) + : type_to_invoke_on (std::move (invoke_on_type)), trait_path (trait_path), + locus (locus), node_id (Analysis::Mappings::get ().get_next_node_id ()) {} // Copy constructor uses custom deep copy for Type to preserve polymorphism @@ -1226,7 +1334,7 @@ public: /* AST node representing a qualified path-in-expression pattern (path that * allows specifying trait functions) */ -class QualifiedPathInExpression : public PathPattern, public PathExpr +class QualifiedPathInExpression : public Path, public ExprWithoutBlock { std::vector<Attribute> outer_attrs; QualifiedPathType path_type; @@ -1240,8 +1348,7 @@ public: std::vector<PathExprSegment> path_segments, std::vector<Attribute> outer_attrs, location_t locus) - : PathPattern (std::move (path_segments)), - outer_attrs (std::move (outer_attrs)), + : Path (std::move (path_segments)), outer_attrs (std::move (outer_attrs)), path_type (std::move (qual_path_type)), locus (locus), _node_id (Analysis::Mappings::get ().get_next_node_id ()) {} @@ -1287,6 +1394,11 @@ public: NodeId get_node_id () const override { return _node_id; } + Expr::Kind get_expr_kind () const override + { + return Expr::Kind::QualifiedPathInExpression; + } + protected: /* Use covariance to implement clone function as returning this object * rather than base */ @@ -1316,7 +1428,7 @@ class QualifiedPathInType : public TypeNoBounds { QualifiedPathType path_type; std::unique_ptr<TypePathSegment> associated_segment; - std::vector<std::unique_ptr<TypePathSegment> > segments; + std::vector<std::unique_ptr<TypePathSegment>> segments; location_t locus; protected: @@ -1331,7 +1443,7 @@ public: QualifiedPathInType ( QualifiedPathType qual_path_type, std::unique_ptr<TypePathSegment> associated_segment, - std::vector<std::unique_ptr<TypePathSegment> > path_segments, + std::vector<std::unique_ptr<TypePathSegment>> path_segments, location_t locus) : path_type (std::move (qual_path_type)), associated_segment (std::move (associated_segment)), @@ -1378,7 +1490,7 @@ public: { return QualifiedPathInType ( QualifiedPathType::create_error (), nullptr, - std::vector<std::unique_ptr<TypePathSegment> > (), UNDEF_LOCATION); + std::vector<std::unique_ptr<TypePathSegment>> (), UNDEF_LOCATION); } std::string as_string () const override; @@ -1398,11 +1510,11 @@ public: } // TODO: this seems kinda dodgy - std::vector<std::unique_ptr<TypePathSegment> > &get_segments () + std::vector<std::unique_ptr<TypePathSegment>> &get_segments () { return segments; } - const std::vector<std::unique_ptr<TypePathSegment> > &get_segments () const + const std::vector<std::unique_ptr<TypePathSegment>> &get_segments () const { return segments; } diff --git a/gcc/rust/ast/rust-pattern.cc b/gcc/rust/ast/rust-pattern.cc index 98fd8e5..fc7b610 100644 --- a/gcc/rust/ast/rust-pattern.cc +++ b/gcc/rust/ast/rust-pattern.cc @@ -22,7 +22,6 @@ along with GCC; see the file COPYING3. If not see #include "rust-diagnostics.h" #include "rust-ast-visitor.h" #include "rust-macro.h" -#include "rust-session-manager.h" #include "rust-lex.h" #include "rust-parse.h" #include "rust-operators.h" diff --git a/gcc/rust/ast/rust-pattern.h b/gcc/rust/ast/rust-pattern.h index 383a5ee..69dbd98 100644 --- a/gcc/rust/ast/rust-pattern.h +++ b/gcc/rust/ast/rust-pattern.h @@ -1657,7 +1657,7 @@ protected: }; // Moved definition to rust-path.h -class PathPattern; +class Path; // Forward decls for paths (defined in rust-path.h) class PathInExpression; diff --git a/gcc/rust/ast/rust-stmt.h b/gcc/rust/ast/rust-stmt.h index e8aec34..f843a79 100644 --- a/gcc/rust/ast/rust-stmt.h +++ b/gcc/rust/ast/rust-stmt.h @@ -19,10 +19,11 @@ #ifndef RUST_AST_STATEMENT_H #define RUST_AST_STATEMENT_H +#include "optional.h" #include "rust-ast.h" #include "rust-path.h" #include "rust-expr.h" -#include <memory> +#include "rust-system.h" namespace Rust { namespace AST { @@ -72,6 +73,8 @@ class LetStmt : public Stmt // bool has_init_expr; std::unique_ptr<Expr> init_expr; + tl::optional<std::unique_ptr<Expr>> else_expr; + location_t locus; public: @@ -85,15 +88,18 @@ public: // Returns whether let statement has an initialisation expression. bool has_init_expr () const { return init_expr != nullptr; } + bool has_else_expr () const { return else_expr.has_value (); } std::string as_string () const override; LetStmt (std::unique_ptr<Pattern> variables_pattern, std::unique_ptr<Expr> init_expr, std::unique_ptr<Type> type, + tl::optional<std::unique_ptr<Expr>> else_expr, std::vector<Attribute> outer_attrs, location_t locus) : outer_attrs (std::move (outer_attrs)), variables_pattern (std::move (variables_pattern)), - type (std::move (type)), init_expr (std::move (init_expr)), locus (locus) + type (std::move (type)), init_expr (std::move (init_expr)), + else_expr (std::move (else_expr)), locus (locus) {} // Copy constructor with clone @@ -107,6 +113,9 @@ public: // guard to prevent null dereference (always required) if (other.init_expr != nullptr) init_expr = other.init_expr->clone_expr (); + if (other.else_expr.has_value ()) + else_expr = other.else_expr.value ()->clone_expr (); + if (other.type != nullptr) type = other.type->clone_type (); } @@ -128,6 +137,12 @@ public: init_expr = other.init_expr->clone_expr (); else init_expr = nullptr; + + if (other.else_expr != nullptr) + else_expr = other.else_expr.value ()->clone_expr (); + else + else_expr = tl::nullopt; + if (other.type != nullptr) type = other.type->clone_type (); else @@ -162,12 +177,24 @@ public: return *init_expr; } + Expr &get_else_expr () + { + rust_assert (has_else_expr ()); + return *else_expr.value (); + } + std::unique_ptr<Expr> &get_init_expr_ptr () { rust_assert (has_init_expr ()); return init_expr; } + std::unique_ptr<Expr> &get_else_expr_ptr () + { + rust_assert (has_else_expr ()); + return else_expr.value (); + } + Pattern &get_pattern () { rust_assert (variables_pattern != nullptr); diff --git a/gcc/rust/ast/rust-type.h b/gcc/rust/ast/rust-type.h index cf830f6..1bb521d 100644 --- a/gcc/rust/ast/rust-type.h +++ b/gcc/rust/ast/rust-type.h @@ -48,6 +48,11 @@ public: std::vector<LifetimeParam> &get_for_lifetimes () { return for_lifetimes; } + const std::vector<LifetimeParam> &get_for_lifetimes () const + { + return for_lifetimes; + } + TraitBound (TypePath type_path, location_t locus, bool in_parens = false, bool opening_question_mark = false, std::vector<LifetimeParam> for_lifetimes @@ -81,6 +86,11 @@ public: bool is_in_parens () const { return in_parens; } bool has_opening_question_mark () const { return opening_question_mark; } + TypeParamBoundType get_bound_type () const override + { + return TypeParamBound::TypeParamBoundType::TRAIT; + } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -532,7 +542,7 @@ protected: class ReferenceType : public TypeNoBounds { // bool has_lifetime; // TODO: handle in lifetime or something? - Lifetime lifetime; + tl::optional<Lifetime> lifetime; bool has_mut; std::unique_ptr<TypeNoBounds> type; @@ -543,11 +553,12 @@ public: bool is_mut () const { return has_mut; } // Returns whether the reference has a lifetime. - bool has_lifetime () const { return !lifetime.is_error (); } + bool has_lifetime () const { return lifetime.has_value (); } // Constructor ReferenceType (bool is_mut, std::unique_ptr<TypeNoBounds> type_no_bounds, - location_t locus, Lifetime lifetime = Lifetime::elided ()) + location_t locus, + tl::optional<Lifetime> lifetime = Lifetime::elided ()) : lifetime (std::move (lifetime)), has_mut (is_mut), type (std::move (type_no_bounds)), locus (locus) {} @@ -588,7 +599,8 @@ public: bool get_has_mut () const { return has_mut; } - Lifetime &get_lifetime () { return lifetime; } + Lifetime &get_lifetime () { return lifetime.value (); } + const Lifetime &get_lifetime () const { return lifetime.value (); } TypeNoBounds &get_base_type () { return *type; } diff --git a/gcc/rust/backend/rust-compile-asm.cc b/gcc/rust/backend/rust-compile-asm.cc new file mode 100644 index 0000000..7351cf0 --- /dev/null +++ b/gcc/rust/backend/rust-compile-asm.cc @@ -0,0 +1,199 @@ +#include "rust-compile-asm.h" +#include "rust-compile-expr.h" +#include "rust-system.h" + +namespace Rust { +namespace Compile { + +CompileAsm::CompileAsm (Context *ctx) : HIRCompileBase (ctx) {} + +tree +CompileAsm::tree_codegen_asm (HIR::InlineAsm &expr) +{ + auto asm_expr + = asm_build_stmt (expr.get_locus (), {asm_construct_string_tree (expr), + asm_construct_outputs (expr), + asm_construct_inputs (expr), + asm_construct_clobber_tree (expr), + asm_construct_label_tree (expr)}); + + ASM_BASIC_P (asm_expr) = expr.is_simple_asm (); + ASM_VOLATILE_P (asm_expr) = false; + ASM_INLINE_P (asm_expr) = expr.is_inline_asm (); + /*Backend::debug (asm_expr);*/ + return asm_expr; +} + +tree +CompileAsm::asm_build_stmt ( + location_t loc, + const std::array<tree, CompileAsm::ASM_TREE_ARRAY_LENGTH> &trees) +{ + // Prototype functiion for building an ASM_EXPR tree. + tree ret; + bool side_effects; + + ret = make_node (ASM_EXPR); + TREE_TYPE (ret) = void_type_node; + SET_EXPR_LOCATION (ret, loc); + + /* TREE_SIDE_EFFECTS will already be set for statements with + implicit side effects. Here we make sure it is set for other + expressions by checking whether the parameters have side + effects. */ + + // This is here because of c-typeck.cc's code + // I'm not sure what kind of effects it has + side_effects = false; + for (size_t i = 0; i < trees.size (); i++) + { + tree t = trees[i]; + if (t && !TYPE_P (t)) + side_effects |= TREE_SIDE_EFFECTS (t); + TREE_OPERAND (ret, i) = t; + } + + TREE_SIDE_EFFECTS (ret) |= side_effects; + + return ret; +} + +tree +CompileAsm::asm_construct_string_tree (HIR::InlineAsm &expr) +{ + // To construct an ASM_EXPR tree, we need to build a STRING_CST tree. + // + // We do this by concatenating all the template strings in the InlineAsm + // into one big std::string seperated by tabs and newlines. (For easier + // debugging and reading) + std::stringstream ss; + for (const auto &template_str : expr.template_strs) + ss << template_str.symbol << "\n"; + + std::string result = ss.str (); + return Backend::string_constant_expression (result); +} + +tree +CompileAsm::asm_construct_outputs (HIR::InlineAsm &expr) +{ + // TODO: Do i need to do this? + + tree head = NULL_TREE; + for (auto &output : expr.get_operands ()) + { + if (output.get_register_type () + == AST::InlineAsmOperand::RegisterType::Out) + { + auto out = output.get_out (); + + tree out_tree = CompileExpr::Compile (*out.expr, this->ctx); + // expects a tree list + // TODO: This assumes that the output is a register + std::string expr_name = "=r"; + auto name = build_string (expr_name.size () + 1, expr_name.c_str ()); + head + = chainon (head, build_tree_list (build_tree_list (NULL_TREE, name), + out_tree)); + + /*Backend::debug (head);*/ + /*head = chainon (head, out_tree);*/ + } + } + return head; +} + +tree +CompileAsm::asm_construct_inputs (HIR::InlineAsm &expr) +{ + // TODO: Do i need to do this? + tree head = NULL_TREE; + for (auto &input : expr.get_operands ()) + { + if (input.get_register_type () == AST::InlineAsmOperand::RegisterType::In) + { + auto in = input.get_in (); + + tree in_tree = CompileExpr::Compile (*in.expr, this->ctx); + // expects a tree list + // TODO: This assumes that the input is a register + std::string expr_name = "r"; + auto name = build_string (expr_name.size () + 1, expr_name.c_str ()); + head + = chainon (head, build_tree_list (build_tree_list (NULL_TREE, name), + in_tree)); + + /*head = chainon (head, out_tree);*/ + } + } + return head; +} + +tree +CompileAsm::asm_construct_clobber_tree (HIR::InlineAsm &expr) +{ + // TODO: Do i need to do this? + return NULL_TREE; +} + +tree +CompileAsm::asm_construct_label_tree (HIR::InlineAsm &expr) +{ + // TODO: Do i need to do this? + return NULL_TREE; +} + +CompileLlvmAsm::CompileLlvmAsm (Context *ctx) : HIRCompileBase (ctx) {} + +tree +CompileLlvmAsm::construct_operands (std::vector<HIR::LlvmOperand> operands) +{ + tree head = NULL_TREE; + for (auto &operand : operands) + { + tree t = CompileExpr::Compile (*operand.expr, this->ctx); + auto name = build_string (operand.constraint.size () + 1, + operand.constraint.c_str ()); + head = chainon (head, + build_tree_list (build_tree_list (NULL_TREE, name), t)); + } + return head; +} + +tree +CompileLlvmAsm::construct_clobbers (std::vector<AST::TupleClobber> clobbers) +{ + tree head = NULL_TREE; + for (auto &clobber : clobbers) + { + auto name + = build_string (clobber.symbol.size () + 1, clobber.symbol.c_str ()); + head = chainon (head, build_tree_list (NULL_TREE, name)); + } + return head; +} + +tree +CompileLlvmAsm::tree_codegen_asm (HIR::LlvmInlineAsm &expr) +{ + tree ret = make_node (ASM_EXPR); + TREE_TYPE (ret) = void_type_node; + SET_EXPR_LOCATION (ret, expr.get_locus ()); + ASM_VOLATILE_P (ret) = expr.options.is_volatile; + + std::stringstream ss; + for (const auto &template_str : expr.templates) + { + ss << template_str.symbol << "\n"; + } + + ASM_STRING (ret) = Backend::string_constant_expression (ss.str ()); + ASM_INPUTS (ret) = construct_operands (expr.inputs); + ASM_OUTPUTS (ret) = construct_operands (expr.outputs); + ASM_CLOBBERS (ret) = construct_clobbers (expr.get_clobbers ()); + + return ret; +} + +} // namespace Compile +} // namespace Rust diff --git a/gcc/rust/backend/rust-compile-asm.h b/gcc/rust/backend/rust-compile-asm.h new file mode 100644 index 0000000..22be94a --- /dev/null +++ b/gcc/rust/backend/rust-compile-asm.h @@ -0,0 +1,75 @@ +// Copyright (C) 2020-2024 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_COMPILE_ASM +#define RUST_COMPILE_ASM + +#include "rust-compile-base.h" +#include "rust-hir-visitor.h" + +namespace Rust { +namespace Compile { + +class CompileAsm : private HIRCompileBase +{ +private: + // RELEVANT MEMBER FUNCTIONS + + // The limit is 5 because it stands for the 5 things that the C version of + // build_asm_expr accepts: string, output, input, clobber and label. + // The function signature is + // + // tree + // build_asm_expr (location_t loc, tree string, tree outputs, tree inputs, + // tree clobbers, tree labels, bool simple, bool is_inline) + static const int ASM_TREE_ARRAY_LENGTH = 5; + tree asm_build_stmt (location_t, + const std::array<tree, ASM_TREE_ARRAY_LENGTH> &); + + tree asm_construct_string_tree (HIR::InlineAsm &); + tree asm_construct_outputs (HIR::InlineAsm &); + tree asm_construct_inputs (HIR::InlineAsm &); + tree asm_construct_clobber_tree (HIR::InlineAsm &); + tree asm_construct_label_tree (HIR::InlineAsm &); + +public: + // WE WILL OPEN THIS UP WHEN WE WANT TO ADD A DEDICATED PASS OF HIR'S ASM + // translation. + // static tree Compile (HIR::Expr *expr, Context *ctx); + + CompileAsm (Context *ctx); + + tree tree_codegen_asm (HIR::InlineAsm &); +}; + +class CompileLlvmAsm : private HIRCompileBase +{ +private: + tree construct_operands (std::vector<HIR::LlvmOperand> operands); + + tree construct_clobbers (std::vector<AST::TupleClobber>); + +public: + CompileLlvmAsm (Context *ctx); + + tree tree_codegen_asm (HIR::LlvmInlineAsm &); +}; + +} // namespace Compile +} // namespace Rust +#endif // RUST_COMPILE_ASM diff --git a/gcc/rust/backend/rust-compile-base.cc b/gcc/rust/backend/rust-compile-base.cc index 8166c3a..12b9561 100644 --- a/gcc/rust/backend/rust-compile-base.cc +++ b/gcc/rust/backend/rust-compile-base.cc @@ -25,7 +25,8 @@ #include "rust-compile-type.h" #include "rust-constexpr.h" #include "rust-diagnostics.h" -#include "rust-expr.h" // for AST::AttrInputLiteral +#include "rust-expr.h" // for AST::AttrInputLiteral +#include "rust-hir-map.h" #include "rust-macro.h" // for AST::MetaNameValueStr #include "rust-hir-path-probe.h" #include "rust-type-util.h" @@ -39,6 +40,9 @@ #include "tree.h" #include "print-tree.h" +// rust-name-resolution-2.0 +#include "options.h" + namespace Rust { namespace Compile { @@ -545,7 +549,7 @@ HIRCompileBase::mark_addressable (tree exp, location_t locus) } tree -HIRCompileBase::address_expression (tree expr, location_t location) +HIRCompileBase::address_expression (tree expr, location_t location, tree ptrty) { if (expr == error_mark_node) return error_mark_node; @@ -553,7 +557,22 @@ HIRCompileBase::address_expression (tree expr, location_t location) if (!mark_addressable (expr, location)) return error_mark_node; - return build_fold_addr_expr_loc (location, expr); + if (ptrty == NULL || ptrty == error_mark_node) + ptrty = build_pointer_type (TREE_TYPE (expr)); + + return build_fold_addr_expr_with_type_loc (location, expr, ptrty); +} + +tree +HIRCompileBase::compile_constant_expr ( + Context *ctx, HirId coercion_id, TyTy::BaseType *resolved_type, + TyTy::BaseType *expected_type, const Resolver::CanonicalPath &canonical_path, + HIR::Expr &const_value_expr, location_t locus, location_t expr_locus) +{ + HIRCompileBase c (ctx); + return c.compile_constant_item (coercion_id, resolved_type, expected_type, + canonical_path, const_value_expr, locus, + expr_locus); } tree @@ -582,8 +601,9 @@ HIRCompileBase::compile_function_body (tree fndecl, if (function_body.has_expr ()) { - location_t locus = function_body.get_final_expr ()->get_locus (); - tree return_value = CompileExpr::Compile (function_body.expr.get (), ctx); + location_t locus = function_body.get_final_expr ().get_locus (); + tree return_value + = CompileExpr::Compile (function_body.get_final_expr (), ctx); // we can only return this if non unit value return type if (!fn_return_ty->is_unit ()) @@ -646,7 +666,8 @@ get_abi (const AST::AttrVec &outer_attrs, tree HIRCompileBase::compile_function ( - const std::string &fn_name, HIR::SelfParam &self_param, + bool is_root_item, const std::string &fn_name, + tl::optional<HIR::SelfParam> &self_param, std::vector<HIR::FunctionParam> &function_params, const HIR::FunctionQualifiers &qualifiers, HIR::Visibility &visibility, AST::AttrVec &outer_attrs, location_t locus, HIR::BlockExpr *function_body, @@ -657,7 +678,7 @@ HIRCompileBase::compile_function ( = canonical_path.get () + fntype->subst_as_string (); // we don't mangle the main fn since we haven't implemented the main shim - bool is_main_fn = fn_name.compare ("main") == 0; + bool is_main_fn = fn_name.compare ("main") == 0 && is_root_item; if (is_main_fn) { rust_assert (!main_identifier_node); @@ -666,6 +687,11 @@ HIRCompileBase::compile_function ( } std::string asm_name = fn_name; + auto &mappings = Analysis::Mappings::get (); + + if (flag_name_resolution_2_0) + ir_symbol_name = mappings.get_current_crate_name () + "::" + ir_symbol_name; + unsigned int flags = 0; tree fndecl = Backend::function (compiled_fn_type, ir_symbol_name, "" /* asm_name */, flags, locus); @@ -688,39 +714,39 @@ HIRCompileBase::compile_function ( // setup the params TyTy::BaseType *tyret = fntype->get_return_type (); std::vector<Bvariable *> param_vars; - if (!self_param.is_error ()) + if (self_param) { rust_assert (fntype->is_method ()); TyTy::BaseType *self_tyty_lookup = fntype->get_self_type (); tree self_type = TyTyResolveCompile::compile (ctx, self_tyty_lookup); Bvariable *compiled_self_param - = CompileSelfParam::compile (ctx, fndecl, self_param, self_type, - self_param.get_locus ()); + = CompileSelfParam::compile (ctx, fndecl, self_param.value (), + self_type, self_param->get_locus ()); param_vars.push_back (compiled_self_param); - ctx->insert_var_decl (self_param.get_mappings ().get_hirid (), + ctx->insert_var_decl (self_param->get_mappings ().get_hirid (), compiled_self_param); } // offset from + 1 for the TyTy::FnType being used when this is a method to // skip over Self on the FnType - bool is_method = !self_param.is_error (); + bool is_method = self_param.has_value (); size_t i = is_method ? 1 : 0; for (auto &referenced_param : function_params) { - auto tyty_param = fntype->param_at (i++); - auto param_tyty = tyty_param.second; + auto &tyty_param = fntype->param_at (i++); + auto param_tyty = tyty_param.get_type (); auto compiled_param_type = TyTyResolveCompile::compile (ctx, param_tyty); location_t param_locus = referenced_param.get_locus (); Bvariable *compiled_param_var - = CompileFnParam::compile (ctx, fndecl, &referenced_param, + = CompileFnParam::compile (ctx, fndecl, referenced_param, compiled_param_type, param_locus); param_vars.push_back (compiled_param_var); - const HIR::Pattern ¶m_pattern = *referenced_param.get_param_name (); + const HIR::Pattern ¶m_pattern = referenced_param.get_param_name (); ctx->insert_var_decl (param_pattern.get_mappings ().get_hirid (), compiled_param_var); } @@ -767,15 +793,20 @@ HIRCompileBase::compile_function ( tree HIRCompileBase::compile_constant_item ( - TyTy::BaseType *resolved_type, const Resolver::CanonicalPath &canonical_path, - HIR::Expr *const_value_expr, location_t locus) + HirId coercion_id, TyTy::BaseType *resolved_type, + TyTy::BaseType *expected_type, const Resolver::CanonicalPath &canonical_path, + HIR::Expr &const_value_expr, location_t locus, location_t expr_locus) { const std::string &ident = canonical_path.get (); tree type = TyTyResolveCompile::compile (ctx, resolved_type); tree const_type = build_qualified_type (type, TYPE_QUAL_CONST); + + tree actual_type = TyTyResolveCompile::compile (ctx, expected_type); + tree actual_const_type = build_qualified_type (actual_type, TYPE_QUAL_CONST); + bool is_block_expr - = const_value_expr->get_expression_type () == HIR::Expr::ExprType::Block; + = const_value_expr.get_expression_type () == HIR::Expr::ExprType::Block; // in order to compile a block expr we want to reuse as much existing // machineary that we already have. This means the best approach is to @@ -789,14 +820,14 @@ HIRCompileBase::compile_constant_item ( TREE_READONLY (fndecl) = 1; tree enclosing_scope = NULL_TREE; - location_t start_location = const_value_expr->get_locus (); - location_t end_location = const_value_expr->get_locus (); + location_t start_location = const_value_expr.get_locus (); + location_t end_location = const_value_expr.get_locus (); if (is_block_expr) { - HIR::BlockExpr *function_body - = static_cast<HIR::BlockExpr *> (const_value_expr); - start_location = function_body->get_locus (); - end_location = function_body->get_end_locus (); + HIR::BlockExpr &function_body + = static_cast<HIR::BlockExpr &> (const_value_expr); + start_location = function_body.get_locus (); + end_location = function_body.get_end_locus (); } tree code_block = Backend::block (fndecl, enclosing_scope, {} /*locals*/, @@ -814,9 +845,9 @@ HIRCompileBase::compile_constant_item ( if (is_block_expr) { - HIR::BlockExpr *function_body - = static_cast<HIR::BlockExpr *> (const_value_expr); - compile_function_body (fndecl, *function_body, resolved_type); + HIR::BlockExpr &function_body + = static_cast<HIR::BlockExpr &> (const_value_expr); + compile_function_body (fndecl, function_body, resolved_type); } else { @@ -824,7 +855,7 @@ HIRCompileBase::compile_constant_item ( tree return_expr = Backend::return_statement (fndecl, value, - const_value_expr->get_locus ()); + const_value_expr.get_locus ()); ctx->add_statement (return_expr); } @@ -841,7 +872,11 @@ HIRCompileBase::compile_constant_item ( tree call = build_call_array_loc (locus, const_type, fndecl, 0, NULL); tree folded_expr = fold_expr (call); - return named_constant_expression (const_type, ident, folded_expr, locus); + // coercion site + tree coerced = coercion_site (coercion_id, folded_expr, resolved_type, + expected_type, locus, expr_locus); + + return named_constant_expression (actual_const_type, ident, coerced, locus); } tree @@ -992,7 +1027,7 @@ HIRCompileBase::resolve_method_address (TyTy::FnType *fntype, tree HIRCompileBase::unit_expression (location_t locus) { - tree unit_type = TyTyResolveCompile::get_unit_type (); + tree unit_type = TyTyResolveCompile::get_unit_type (ctx); return Backend::constructor_expression (unit_type, false, {}, -1, locus); } diff --git a/gcc/rust/backend/rust-compile-base.h b/gcc/rust/backend/rust-compile-base.h index eeb3ff0..6814abc 100644 --- a/gcc/rust/backend/rust-compile-base.h +++ b/gcc/rust/backend/rust-compile-base.h @@ -29,7 +29,14 @@ class HIRCompileBase public: virtual ~HIRCompileBase () {} - static tree address_expression (tree expr, location_t locus); + static tree address_expression (tree expr, location_t locus, + tree ptrty = NULL_TREE); + + static tree compile_constant_expr ( + Context *ctx, HirId coercion_id, TyTy::BaseType *resolved_type, + TyTy::BaseType *expected_type, + const Resolver::CanonicalPath &canonical_path, HIR::Expr &const_value_expr, + location_t locus, location_t expr_locus); protected: HIRCompileBase (Context *ctx) : ctx (ctx) {} @@ -90,11 +97,14 @@ protected: void compile_function_body (tree fndecl, HIR::BlockExpr &function_body, TyTy::BaseType *fn_return_ty); - tree compile_constant_item (TyTy::BaseType *resolved_type, + tree compile_constant_item (HirId coercion_id, TyTy::BaseType *resolved_type, + TyTy::BaseType *expected_type, const Resolver::CanonicalPath &canonical_path, - HIR::Expr *const_value_expr, location_t locus); + HIR::Expr &const_value_expr, location_t locus, + location_t expr_locus); - tree compile_function (const std::string &fn_name, HIR::SelfParam &self_param, + tree compile_function (bool is_root_item, const std::string &fn_name, + tl::optional<HIR::SelfParam> &self_param, std::vector<HIR::FunctionParam> &function_params, const HIR::FunctionQualifiers &qualifiers, HIR::Visibility &visibility, AST::AttrVec &outer_attrs, @@ -102,7 +112,7 @@ protected: const Resolver::CanonicalPath &canonical_path, TyTy::FnType *fntype); - static tree unit_expression (location_t locus); + tree unit_expression (location_t locus); void setup_fndecl (tree fndecl, bool is_main_entry_point, bool is_generic_fn, HIR::Visibility &visibility, diff --git a/gcc/rust/backend/rust-compile-block.cc b/gcc/rust/backend/rust-compile-block.cc index eb8af2a..f844a27 100644 --- a/gcc/rust/backend/rust-compile-block.cc +++ b/gcc/rust/backend/rust-compile-block.cc @@ -28,10 +28,10 @@ CompileBlock::CompileBlock (Context *ctx, Bvariable *result) {} tree -CompileBlock::compile (HIR::BlockExpr *expr, Context *ctx, Bvariable *result) +CompileBlock::compile (HIR::BlockExpr &expr, Context *ctx, Bvariable *result) { CompileBlock compiler (ctx, result); - compiler.visit (*expr); + compiler.visit (expr); return compiler.translated; } @@ -60,10 +60,10 @@ CompileBlock::visit (HIR::BlockExpr &expr) if (expr.has_expr ()) { - tree compiled_expr = CompileExpr::Compile (expr.expr.get (), ctx); + tree compiled_expr = CompileExpr::Compile (expr.get_final_expr (), ctx); if (result != nullptr) { - location_t locus = expr.get_final_expr ()->get_locus (); + location_t locus = expr.get_final_expr ().get_locus (); tree result_reference = Backend::var_expression (result, locus); tree assignment @@ -93,10 +93,8 @@ CompileConditionalBlocks::visit (HIR::IfExpr &expr) { fncontext fnctx = ctx->peek_fn (); tree fndecl = fnctx.fndecl; - tree condition_expr - = CompileExpr::Compile (expr.get_if_condition ().get (), ctx); - tree then_block - = CompileBlock::compile (expr.get_if_block ().get (), ctx, result); + tree condition_expr = CompileExpr::Compile (expr.get_if_condition (), ctx); + tree then_block = CompileBlock::compile (expr.get_if_block (), ctx, result); translated = Backend::if_statement (fndecl, condition_expr, then_block, NULL, expr.get_locus ()); @@ -107,23 +105,20 @@ CompileConditionalBlocks::visit (HIR::IfExprConseqElse &expr) { fncontext fnctx = ctx->peek_fn (); tree fndecl = fnctx.fndecl; - tree condition_expr - = CompileExpr::Compile (expr.get_if_condition ().get (), ctx); - tree then_block - = CompileBlock::compile (expr.get_if_block ().get (), ctx, result); + tree condition_expr = CompileExpr::Compile (expr.get_if_condition (), ctx); + tree then_block = CompileBlock::compile (expr.get_if_block (), ctx, result); // else block std::vector<Bvariable *> locals; - location_t start_location = expr.get_else_block ()->get_locus (); - location_t end_location = expr.get_else_block ()->get_locus (); // FIXME + location_t start_location = expr.get_else_block ().get_locus (); + location_t end_location = expr.get_else_block ().get_locus (); // FIXME tree enclosing_scope = ctx->peek_enclosing_scope (); tree else_block = Backend::block (fndecl, enclosing_scope, locals, start_location, end_location); ctx->push_block (else_block); tree else_stmt_decl - = CompileExprWithBlock::compile (expr.get_else_block ().get (), ctx, - result); + = CompileExprWithBlock::compile (&expr.get_else_block (), ctx, result); ctx->add_statement (else_stmt_decl); diff --git a/gcc/rust/backend/rust-compile-block.h b/gcc/rust/backend/rust-compile-block.h index b315c77..3f38d08 100644 --- a/gcc/rust/backend/rust-compile-block.h +++ b/gcc/rust/backend/rust-compile-block.h @@ -28,7 +28,7 @@ namespace Compile { class CompileBlock : private HIRCompileBase { public: - static tree compile (HIR::BlockExpr *expr, Context *ctx, Bvariable *result); + static tree compile (HIR::BlockExpr &expr, Context *ctx, Bvariable *result); protected: void visit (HIR::BlockExpr &expr); @@ -96,11 +96,11 @@ public: void visit (HIR::LoopExpr &) override {} void visit (HIR::WhileLoopExpr &) override {} void visit (HIR::WhileLetLoopExpr &) override {} - void visit (HIR::IfLetExpr &) override {} - void visit (HIR::IfLetExprConseqElse &) override {} void visit (HIR::MatchExpr &) override {} void visit (HIR::AwaitExpr &) override {} void visit (HIR::AsyncBlockExpr &) override {} + void visit (HIR::InlineAsm &) override {} + void visit (HIR::LlvmInlineAsm &) override {} private: CompileConditionalBlocks (Context *ctx, Bvariable *result) @@ -135,7 +135,7 @@ public: void visit (HIR::BlockExpr &expr) override { - translated = CompileBlock::compile (&expr, ctx, result); + translated = CompileBlock::compile (expr, ctx, result); } // Empty visit for unused Expression HIR nodes. @@ -179,11 +179,11 @@ public: void visit (HIR::LoopExpr &) override {} void visit (HIR::WhileLoopExpr &) override {} void visit (HIR::WhileLetLoopExpr &) override {} - void visit (HIR::IfLetExpr &) override {} - void visit (HIR::IfLetExprConseqElse &) override {} void visit (HIR::MatchExpr &) override {} void visit (HIR::AwaitExpr &) override {} void visit (HIR::AsyncBlockExpr &) override {} + void visit (HIR::InlineAsm &) override {} + void visit (HIR::LlvmInlineAsm &) override {} private: CompileExprWithBlock (Context *ctx, Bvariable *result) diff --git a/gcc/rust/backend/rust-compile-context.cc b/gcc/rust/backend/rust-compile-context.cc index c80f956..86f0894 100644 --- a/gcc/rust/backend/rust-compile-context.cc +++ b/gcc/rust/backend/rust-compile-context.cc @@ -33,19 +33,8 @@ Context::Context () void Context::setup_builtins () { - auto builtins = resolver->get_builtin_types (); - for (auto it = builtins.begin (); it != builtins.end (); it++) - { - HirId ref; - bool ok = tyctx->lookup_type_by_node_id ((*it)->get_node_id (), &ref); - rust_assert (ok); - - TyTy::BaseType *lookup; - ok = tyctx->lookup_type (ref, &lookup); - rust_assert (ok); - - TyTyResolveCompile::compile (this, lookup); - } + for (auto &builtin : tyctx->get_builtins ()) + TyTyResolveCompile::compile (this, builtin.get ()); } hashval_t diff --git a/gcc/rust/backend/rust-compile-context.h b/gcc/rust/backend/rust-compile-context.h index a446388..ce81a1d 100644 --- a/gcc/rust/backend/rust-compile-context.h +++ b/gcc/rust/backend/rust-compile-context.h @@ -72,7 +72,10 @@ public: return it->second; compiled_type_map.insert ({h, type}); - push_type (type); + + if (TYPE_NAME (type) != NULL) + push_type (type); + return type; } diff --git a/gcc/rust/backend/rust-compile-expr.cc b/gcc/rust/backend/rust-compile-expr.cc index e2fa6dd..dd3420f 100644 --- a/gcc/rust/backend/rust-compile-expr.cc +++ b/gcc/rust/backend/rust-compile-expr.cc @@ -25,12 +25,13 @@ #include "rust-constexpr.h" #include "rust-compile-type.h" #include "rust-gcc.h" - +#include "rust-compile-asm.h" #include "fold-const.h" #include "realmpfr.h" #include "convert.h" #include "print-tree.h" #include "rust-system.h" +#include "rust-tyty.h" namespace Rust { namespace Compile { @@ -40,24 +41,24 @@ CompileExpr::CompileExpr (Context *ctx) {} tree -CompileExpr::Compile (HIR::Expr *expr, Context *ctx) +CompileExpr::Compile (HIR::Expr &expr, Context *ctx) { CompileExpr compiler (ctx); - expr->accept_vis (compiler); + expr.accept_vis (compiler); return compiler.translated; } void CompileExpr::visit (HIR::TupleIndexExpr &expr) { - HIR::Expr *tuple_expr = expr.get_tuple_expr ().get (); + HIR::Expr &tuple_expr = expr.get_tuple_expr (); TupleIndex index = expr.get_tuple_index (); tree receiver_ref = CompileExpr::Compile (tuple_expr, ctx); TyTy::BaseType *tuple_expr_ty = nullptr; bool ok - = ctx->get_tyctx ()->lookup_type (tuple_expr->get_mappings ().get_hirid (), + = ctx->get_tyctx ()->lookup_type (tuple_expr.get_mappings ().get_hirid (), &tuple_expr_ty); rust_assert (ok); @@ -97,7 +98,7 @@ CompileExpr::visit (HIR::TupleExpr &expr) std::vector<tree> vals; for (auto &elem : expr.get_tuple_elems ()) { - auto e = CompileExpr::Compile (elem.get (), ctx); + auto e = CompileExpr::Compile (*elem, ctx); vals.push_back (e); } @@ -111,7 +112,7 @@ CompileExpr::visit (HIR::ReturnExpr &expr) auto fncontext = ctx->peek_fn (); tree return_value = expr.has_return_expr () - ? CompileExpr::Compile (expr.return_expr.get (), ctx) + ? CompileExpr::Compile (expr.get_expr (), ctx) : unit_expression (expr.get_locus ()); if (expr.has_return_expr ()) @@ -141,8 +142,8 @@ void CompileExpr::visit (HIR::ArithmeticOrLogicalExpr &expr) { auto op = expr.get_expr_type (); - auto lhs = CompileExpr::Compile (expr.get_lhs ().get (), ctx); - auto rhs = CompileExpr::Compile (expr.get_rhs ().get (), ctx); + auto lhs = CompileExpr::Compile (expr.get_lhs (), ctx); + auto rhs = CompileExpr::Compile (expr.get_rhs (), ctx); // this might be an operator overload situation lets check TyTy::FnType *fntype; @@ -152,41 +153,42 @@ CompileExpr::visit (HIR::ArithmeticOrLogicalExpr &expr) { auto lang_item_type = LangItem::OperatorToLangItem (expr.get_expr_type ()); - translated = resolve_operator_overload (lang_item_type, expr, lhs, rhs, - expr.get_lhs ().get (), - expr.get_rhs ().get ()); + translated = resolve_operator_overload ( + lang_item_type, expr, lhs, rhs, expr.get_lhs (), + tl::optional<std::reference_wrapper<HIR::Expr>> (expr.get_rhs ())); return; } - if (ctx->in_fn () && !ctx->const_context_p ()) - { - auto receiver_tmp = NULL_TREE; - auto receiver - = Backend::temporary_variable (ctx->peek_fn ().fndecl, NULL_TREE, - TREE_TYPE (lhs), lhs, true, - expr.get_locus (), &receiver_tmp); - auto check - = Backend::arithmetic_or_logical_expression_checked (op, lhs, rhs, - expr.get_locus (), - receiver); - - ctx->add_statement (check); - translated = receiver->get_tree (expr.get_locus ()); - } - else + bool can_generate_overflow_checks + = (ctx->in_fn () && !ctx->const_context_p ()) && flag_overflow_checks; + if (!can_generate_overflow_checks) { translated = Backend::arithmetic_or_logical_expression (op, lhs, rhs, expr.get_locus ()); + return; } + + auto receiver_tmp = NULL_TREE; + auto receiver + = Backend::temporary_variable (ctx->peek_fn ().fndecl, NULL_TREE, + TREE_TYPE (lhs), lhs, true, + expr.get_locus (), &receiver_tmp); + auto check + = Backend::arithmetic_or_logical_expression_checked (op, lhs, rhs, + expr.get_locus (), + receiver); + + ctx->add_statement (check); + translated = receiver->get_tree (expr.get_locus ()); } void CompileExpr::visit (HIR::CompoundAssignmentExpr &expr) { auto op = expr.get_expr_type (); - auto lhs = CompileExpr::Compile (expr.get_lhs ().get (), ctx); - auto rhs = CompileExpr::Compile (expr.get_rhs ().get (), ctx); + auto lhs = CompileExpr::Compile (expr.get_lhs (), ctx); + auto rhs = CompileExpr::Compile (expr.get_rhs (), ctx); // this might be an operator overload situation lets check TyTy::FnType *fntype; @@ -198,8 +200,7 @@ CompileExpr::visit (HIR::CompoundAssignmentExpr &expr) expr.get_expr_type ()); auto compound_assignment = resolve_operator_overload (lang_item_type, expr, lhs, rhs, - expr.get_lhs ().get (), - expr.get_rhs ().get ()); + expr.get_lhs (), expr.get_rhs ()); ctx->add_statement (compound_assignment); return; @@ -235,7 +236,25 @@ void CompileExpr::visit (HIR::NegationExpr &expr) { auto op = expr.get_expr_type (); - auto negated_expr = CompileExpr::Compile (expr.get_expr ().get (), ctx); + + auto &literal_expr = expr.get_expr (); + + // If it's a negated integer/float literal, we can return early + if (op == NegationOperator::NEGATE + && literal_expr.get_expression_type () == HIR::Expr::ExprType::Lit) + { + auto &new_literal_expr = static_cast<HIR::LiteralExpr &> (literal_expr); + auto lit_type = new_literal_expr.get_lit_type (); + if (lit_type == HIR::Literal::LitType::INT + || lit_type == HIR::Literal::LitType::FLOAT) + { + new_literal_expr.set_negative (); + translated = CompileExpr::Compile (literal_expr, ctx); + return; + } + } + + auto negated_expr = CompileExpr::Compile (literal_expr, ctx); auto location = expr.get_locus (); // this might be an operator overload situation lets check @@ -247,7 +266,7 @@ CompileExpr::visit (HIR::NegationExpr &expr) auto lang_item_type = LangItem::NegationOperatorToLangItem (op); translated = resolve_operator_overload (lang_item_type, expr, negated_expr, - nullptr, expr.get_expr ().get (), nullptr); + nullptr, expr.get_expr (), tl::nullopt); return; } @@ -258,10 +277,30 @@ void CompileExpr::visit (HIR::ComparisonExpr &expr) { auto op = expr.get_expr_type (); - auto lhs = CompileExpr::Compile (expr.get_lhs ().get (), ctx); - auto rhs = CompileExpr::Compile (expr.get_rhs ().get (), ctx); + auto lhs = CompileExpr::Compile (expr.get_lhs (), ctx); + auto rhs = CompileExpr::Compile (expr.get_rhs (), ctx); auto location = expr.get_locus (); + // this might be an operator overload situation lets check + TyTy::FnType *fntype; + bool is_op_overload = ctx->get_tyctx ()->lookup_operator_overload ( + expr.get_mappings ().get_hirid (), &fntype); + if (is_op_overload) + { + auto seg_name = LangItem::ComparisonToSegment (expr.get_expr_type ()); + auto segment = HIR::PathIdentSegment (seg_name); + auto lang_item_type + = LangItem::ComparisonToLangItem (expr.get_expr_type ()); + + rhs = address_expression (rhs, EXPR_LOCATION (rhs)); + + translated = resolve_operator_overload ( + lang_item_type, expr, lhs, rhs, expr.get_lhs (), + tl::optional<std::reference_wrapper<HIR::Expr>> (expr.get_rhs ()), + segment); + return; + } + translated = Backend::comparison_expression (op, lhs, rhs, location); } @@ -269,8 +308,8 @@ void CompileExpr::visit (HIR::LazyBooleanExpr &expr) { auto op = expr.get_expr_type (); - auto lhs = CompileExpr::Compile (expr.get_lhs ().get (), ctx); - auto rhs = CompileExpr::Compile (expr.get_rhs ().get (), ctx); + auto lhs = CompileExpr::Compile (expr.get_lhs (), ctx); + auto rhs = CompileExpr::Compile (expr.get_rhs (), ctx); auto location = expr.get_locus (); translated = Backend::lazy_boolean_expression (op, lhs, rhs, location); @@ -289,14 +328,14 @@ CompileExpr::visit (HIR::TypeCastExpr &expr) TyTy::BaseType *casted_tyty = nullptr; if (!ctx->get_tyctx ()->lookup_type ( - expr.get_casted_expr ()->get_mappings ().get_hirid (), &casted_tyty)) + expr.get_casted_expr ().get_mappings ().get_hirid (), &casted_tyty)) { translated = error_mark_node; return; } auto type_to_cast_to = TyTyResolveCompile::compile (ctx, type_to_cast_to_ty); - auto casted_expr = CompileExpr::Compile (expr.get_casted_expr ().get (), ctx); + auto casted_expr = CompileExpr::Compile (expr.get_casted_expr (), ctx); std::vector<Resolver::Adjustment> *adjustments = nullptr; bool ok = ctx->get_tyctx ()->lookup_cast_autoderef_mappings ( @@ -319,6 +358,23 @@ CompileExpr::visit (HIR::IfExpr &expr) } void +CompileExpr::visit (HIR::InlineAsm &expr) +{ + CompileAsm asm_codegen (ctx); + ctx->add_statement (asm_codegen.tree_codegen_asm (expr)); + // translated = build_asm_expr (0, NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE, + // NULL_TREE, true, true); + // CompileAsm::asm_build_expr (expr); +} + +void +CompileExpr::visit (HIR::LlvmInlineAsm &expr) +{ + CompileLlvmAsm asm_codegen (ctx); + ctx->add_statement (asm_codegen.tree_codegen_asm (expr)); +} + +void CompileExpr::visit (HIR::IfExprConseqElse &expr) { TyTy::BaseType *if_type = nullptr; @@ -377,7 +433,7 @@ CompileExpr::visit (HIR::BlockExpr &expr) &ret_var_stmt); ctx->add_statement (ret_var_stmt); - auto block_stmt = CompileBlock::compile (&expr, ctx, tmp); + auto block_stmt = CompileBlock::compile (expr, ctx, tmp); rust_assert (TREE_CODE (block_stmt) == BIND_EXPR); ctx->add_statement (block_stmt); @@ -387,7 +443,7 @@ CompileExpr::visit (HIR::BlockExpr &expr) void CompileExpr::visit (HIR::UnsafeBlockExpr &expr) { - expr.get_block_expr ()->accept_vis (*this); + expr.get_block_expr ().accept_vis (*this); } void @@ -459,7 +515,7 @@ CompileExpr::visit (HIR::StructExprStructFields &struct_expr) auto lvalue_locus = ctx->get_mappings ().lookup_location (expected->get_ty_ref ()); auto rvalue_locus = argument->get_locus (); - auto rvalue = CompileStructExprField::Compile (argument.get (), ctx); + auto rvalue = CompileStructExprField::Compile (*argument, ctx); TyTy::BaseType *actual = nullptr; bool ok = ctx->get_tyctx ()->lookup_type ( @@ -491,7 +547,7 @@ CompileExpr::visit (HIR::StructExprStructFields &struct_expr) auto lvalue_locus = ctx->get_mappings ().lookup_location (expected->get_ty_ref ()); auto rvalue_locus = argument->get_locus (); - auto rvalue = CompileStructExprField::Compile (argument.get (), ctx); + auto rvalue = CompileStructExprField::Compile (*argument, ctx); TyTy::BaseType *actual = nullptr; bool ok = ctx->get_tyctx ()->lookup_type ( @@ -511,45 +567,53 @@ CompileExpr::visit (HIR::StructExprStructFields &struct_expr) } } - // the constructor depends on whether this is actually an enum or not if - // its an enum we need to setup the discriminator - std::vector<tree> ctor_arguments; - if (adt->is_enum ()) + if (!adt->is_enum ()) { - HIR::Expr *discrim_expr = variant->get_discriminant (); - tree discrim_expr_node = CompileExpr::Compile (discrim_expr, ctx); - tree folded_discrim_expr = fold_expr (discrim_expr_node); - tree qualifier = folded_discrim_expr; - - ctor_arguments.push_back (qualifier); + translated + = Backend::constructor_expression (compiled_adt_type, adt->is_enum (), + arguments, union_disriminator, + struct_expr.get_locus ()); + return; } - for (auto &arg : arguments) - ctor_arguments.push_back (arg); + + HIR::Expr &discrim_expr = variant->get_discriminant (); + tree discrim_expr_node = CompileExpr::Compile (discrim_expr, ctx); + tree folded_discrim_expr = fold_expr (discrim_expr_node); + tree qualifier = folded_discrim_expr; + + tree enum_root_files = TYPE_FIELDS (compiled_adt_type); + tree payload_root = DECL_CHAIN (enum_root_files); + + tree payload = Backend::constructor_expression (TREE_TYPE (payload_root), + adt->is_enum (), arguments, + union_disriminator, + struct_expr.get_locus ()); + + std::vector<tree> ctor_arguments = {qualifier, payload}; translated - = Backend::constructor_expression (compiled_adt_type, adt->is_enum (), - ctor_arguments, union_disriminator, + = Backend::constructor_expression (compiled_adt_type, 0, ctor_arguments, -1, struct_expr.get_locus ()); } void CompileExpr::visit (HIR::GroupedExpr &expr) { - translated = CompileExpr::Compile (expr.get_expr_in_parens ().get (), ctx); + translated = CompileExpr::Compile (expr.get_expr_in_parens (), ctx); } void CompileExpr::visit (HIR::FieldAccessExpr &expr) { - HIR::Expr *receiver_expr = expr.get_receiver_expr ().get (); + HIR::Expr &receiver_expr = expr.get_receiver_expr (); tree receiver_ref = CompileExpr::Compile (receiver_expr, ctx); // resolve the receiver back to ADT type TyTy::BaseType *receiver = nullptr; if (!ctx->get_tyctx ()->lookup_type ( - expr.get_receiver_expr ()->get_mappings ().get_hirid (), &receiver)) + expr.get_receiver_expr ().get_mappings ().get_hirid (), &receiver)) { - rust_error_at (expr.get_receiver_expr ()->get_locus (), + rust_error_at (expr.get_receiver_expr ().get_locus (), "unresolved type for receiver"); return; } @@ -644,7 +708,7 @@ CompileExpr::visit (HIR::LoopExpr &expr) ctx->push_loop_begin_label (loop_begin_label); tree code_block - = CompileBlock::compile (expr.get_loop_block ().get (), ctx, nullptr); + = CompileBlock::compile (expr.get_loop_block (), ctx, nullptr); tree loop_expr = Backend::loop_expression (code_block, expr.get_locus ()); ctx->add_statement (loop_expr); @@ -671,8 +735,8 @@ CompileExpr::visit (HIR::WhileLoopExpr &expr) } std::vector<Bvariable *> locals; - location_t start_location = expr.get_loop_block ()->get_locus (); - location_t end_location = expr.get_loop_block ()->get_locus (); // FIXME + location_t start_location = expr.get_loop_block ().get_locus (); + location_t end_location = expr.get_loop_block ().get_locus (); // FIXME tree enclosing_scope = ctx->peek_enclosing_scope (); tree loop_block = Backend::block (fnctx.fndecl, enclosing_scope, locals, @@ -685,15 +749,14 @@ CompileExpr::visit (HIR::WhileLoopExpr &expr) ctx->add_statement (loop_begin_label_decl); ctx->push_loop_begin_label (loop_begin_label); - tree condition - = CompileExpr::Compile (expr.get_predicate_expr ().get (), ctx); + tree condition = CompileExpr::Compile (expr.get_predicate_expr (), ctx); tree exit_condition = fold_build1_loc (expr.get_locus (), TRUTH_NOT_EXPR, boolean_type_node, condition); tree exit_expr = Backend::exit_expression (exit_condition, expr.get_locus ()); ctx->add_statement (exit_expr); tree code_block_stmt - = CompileBlock::compile (expr.get_loop_block ().get (), ctx, nullptr); + = CompileBlock::compile (expr.get_loop_block (), ctx, nullptr); rust_assert (TREE_CODE (code_block_stmt) == BIND_EXPR); ctx->add_statement (code_block_stmt); @@ -709,12 +772,12 @@ CompileExpr::visit (HIR::BreakExpr &expr) { if (expr.has_break_expr ()) { - tree compiled_expr = CompileExpr::Compile (expr.get_expr ().get (), ctx); + tree compiled_expr = CompileExpr::Compile (expr.get_expr (), ctx); Bvariable *loop_result_holder = ctx->peek_loop_context (); tree result_reference = Backend::var_expression (loop_result_holder, - expr.get_expr ()->get_locus ()); + expr.get_expr ().get_locus ()); tree assignment = Backend::assignment_statement (result_reference, compiled_expr, @@ -725,8 +788,24 @@ CompileExpr::visit (HIR::BreakExpr &expr) if (expr.has_label ()) { NodeId resolved_node_id = UNKNOWN_NODEID; - if (!ctx->get_resolver ()->lookup_resolved_label ( - expr.get_label ().get_mappings ().get_nodeid (), &resolved_node_id)) + if (flag_name_resolution_2_0) + { + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); + + if (auto id + = nr_ctx.lookup (expr.get_label ().get_mappings ().get_nodeid ())) + resolved_node_id = *id; + } + else + { + NodeId tmp = UNKNOWN_NODEID; + if (ctx->get_resolver ()->lookup_resolved_label ( + expr.get_label ().get_mappings ().get_nodeid (), &tmp)) + resolved_node_id = tmp; + } + + if (resolved_node_id == UNKNOWN_NODEID) { rust_error_at ( expr.get_label ().get_locus (), @@ -771,8 +850,25 @@ CompileExpr::visit (HIR::ContinueExpr &expr) if (expr.has_label ()) { NodeId resolved_node_id = UNKNOWN_NODEID; - if (!ctx->get_resolver ()->lookup_resolved_label ( - expr.get_label ().get_mappings ().get_nodeid (), &resolved_node_id)) + if (flag_name_resolution_2_0) + { + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); + + if (auto id + = nr_ctx.lookup (expr.get_label ().get_mappings ().get_nodeid ())) + resolved_node_id = *id; + } + else + { + NodeId tmp = UNKNOWN_NODEID; + + if (ctx->get_resolver ()->lookup_resolved_label ( + expr.get_label ().get_mappings ().get_nodeid (), &tmp)) + resolved_node_id = tmp; + } + + if (resolved_node_id == UNKNOWN_NODEID) { rust_error_at ( expr.get_label ().get_locus (), @@ -804,7 +900,7 @@ CompileExpr::visit (HIR::ContinueExpr &expr) void CompileExpr::visit (HIR::BorrowExpr &expr) { - tree main_expr = CompileExpr::Compile (expr.get_expr ().get (), ctx); + tree main_expr = CompileExpr::Compile (expr.get_expr (), ctx); if (RS_DST_FLAG_P (TREE_TYPE (main_expr))) { translated = main_expr; @@ -816,7 +912,8 @@ CompileExpr::visit (HIR::BorrowExpr &expr) &tyty)) return; - translated = address_expression (main_expr, expr.get_locus ()); + tree expected_type = TyTyResolveCompile::compile (ctx, tyty); + translated = address_expression (main_expr, expr.get_locus (), expected_type); } void @@ -831,7 +928,7 @@ CompileExpr::visit (HIR::DereferenceExpr &expr) return; } - tree main_expr = CompileExpr::Compile (expr.get_expr ().get (), ctx); + tree main_expr = CompileExpr::Compile (expr.get_expr (), ctx); // this might be an operator overload situation lets check TyTy::FnType *fntype; @@ -842,7 +939,7 @@ CompileExpr::visit (HIR::DereferenceExpr &expr) auto lang_item_type = LangItem::Kind::DEREF; tree operator_overload_call = resolve_operator_overload (lang_item_type, expr, main_expr, nullptr, - expr.get_expr ().get (), nullptr); + expr.get_expr (), tl::nullopt); // rust deref always returns a reference from this overload then we can // actually do the indirection @@ -902,8 +999,8 @@ CompileExpr::visit (HIR::LiteralExpr &expr) void CompileExpr::visit (HIR::AssignmentExpr &expr) { - auto lvalue = CompileExpr::Compile (expr.get_lhs ().get (), ctx); - auto rvalue = CompileExpr::Compile (expr.get_rhs ().get (), ctx); + auto lvalue = CompileExpr::Compile (expr.get_lhs (), ctx); + auto rvalue = CompileExpr::Compile (expr.get_rhs (), ctx); // assignments are coercion sites so lets convert the rvalue if necessary TyTy::BaseType *expected = nullptr; @@ -911,16 +1008,16 @@ CompileExpr::visit (HIR::AssignmentExpr &expr) bool ok; ok = ctx->get_tyctx ()->lookup_type ( - expr.get_lhs ()->get_mappings ().get_hirid (), &expected); + expr.get_lhs ().get_mappings ().get_hirid (), &expected); rust_assert (ok); ok = ctx->get_tyctx ()->lookup_type ( - expr.get_rhs ()->get_mappings ().get_hirid (), &actual); + expr.get_rhs ().get_mappings ().get_hirid (), &actual); rust_assert (ok); rvalue = coercion_site (expr.get_mappings ().get_hirid (), rvalue, actual, - expected, expr.get_lhs ()->get_locus (), - expr.get_rhs ()->get_locus ()); + expected, expr.get_lhs ().get_locus (), + expr.get_rhs ().get_locus ()); // rust_debug_loc (expr.get_locus (), "XXXXXX assignment"); // debug_tree (rvalue); @@ -941,30 +1038,15 @@ check_match_scrutinee (HIR::MatchExpr &expr, Context *ctx) { TyTy::BaseType *scrutinee_expr_tyty = nullptr; if (!ctx->get_tyctx ()->lookup_type ( - expr.get_scrutinee_expr ()->get_mappings ().get_hirid (), + expr.get_scrutinee_expr ().get_mappings ().get_hirid (), &scrutinee_expr_tyty)) { return TyTy::TypeKind::ERROR; } TyTy::TypeKind scrutinee_kind = scrutinee_expr_tyty->get_kind (); - rust_assert ((TyTy::is_primitive_type_kind (scrutinee_kind) - && scrutinee_kind != TyTy::TypeKind::NEVER) - || scrutinee_kind == TyTy::TypeKind::ADT - || scrutinee_kind == TyTy::TypeKind::TUPLE - || scrutinee_kind == TyTy::TypeKind::REF); - - if (scrutinee_kind == TyTy::TypeKind::ADT) - { - // this will need to change but for now the first pass implementation, - // lets assert this is the case - TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (scrutinee_expr_tyty); - if (adt->is_enum ()) - rust_assert (adt->number_of_variants () > 0); - else - rust_assert (adt->number_of_variants () == 1); - } - else if (scrutinee_kind == TyTy::TypeKind::FLOAT) + + if (scrutinee_kind == TyTy::TypeKind::FLOAT) { // FIXME: CASE_LABEL_EXPR does not support floating point types. // Find another way to compile these. @@ -1005,6 +1087,15 @@ CompileExpr::visit (HIR::MatchExpr &expr) return; } + // if the result of this expression is meant to be never type then we can + // optimise this away but there is the case where match arms resolve to ! + // because of return statements we need to special case this + if (!expr.has_match_arms () && expr_tyty->is<TyTy::NeverType> ()) + { + translated = unit_expression (expr.get_locus ()); + return; + } + fncontext fnctx = ctx->peek_fn (); Bvariable *tmp = NULL; tree enclosing_scope = ctx->peek_enclosing_scope (); @@ -1019,7 +1110,7 @@ CompileExpr::visit (HIR::MatchExpr &expr) // lets compile the scrutinee expression tree match_scrutinee_rval - = CompileExpr::Compile (expr.get_scrutinee_expr ().get (), ctx); + = CompileExpr::Compile (expr.get_scrutinee_expr (), ctx); Bvariable *match_scrutinee_tmp_var = Backend::temporary_variable (fnctx.fndecl, enclosing_scope, @@ -1029,7 +1120,7 @@ CompileExpr::visit (HIR::MatchExpr &expr) ctx->add_statement (ret_var_stmt); tree match_scrutinee_expr = match_scrutinee_tmp_var->get_tree ( - expr.get_scrutinee_expr ()->get_locus ()); + expr.get_scrutinee_expr ().get_locus ()); tree assignment = Backend::assignment_statement (match_scrutinee_expr, match_scrutinee_rval, @@ -1062,17 +1153,27 @@ CompileExpr::visit (HIR::MatchExpr &expr) ctx->push_block (arm_body_block); // setup the bindings for the block - CompilePatternBindings::Compile (kase_pattern.get (), - match_scrutinee_expr, ctx); + CompilePatternBindings::Compile (*kase_pattern, match_scrutinee_expr, + ctx); // compile the expr and setup the assignment if required when tmp != // NULL location_t arm_locus = kase_arm.get_locus (); - tree kase_expr_tree - = CompileExpr::Compile (kase.get_expr ().get (), ctx); + tree kase_expr_tree = CompileExpr::Compile (kase.get_expr (), ctx); tree result_reference = Backend::var_expression (tmp, arm_locus); + + TyTy::BaseType *actual = nullptr; + bool ok = ctx->get_tyctx ()->lookup_type ( + kase.get_expr ().get_mappings ().get_hirid (), &actual); + rust_assert (ok); + + tree coerced_result + = coercion_site (kase.get_expr ().get_mappings ().get_hirid (), + kase_expr_tree, actual, expr_tyty, + expr.get_locus (), arm_locus); + tree assignment - = Backend::assignment_statement (result_reference, kase_expr_tree, + = Backend::assignment_statement (result_reference, coerced_result, arm_locus); ctx->add_statement (assignment); @@ -1084,7 +1185,7 @@ CompileExpr::visit (HIR::MatchExpr &expr) ctx->pop_block (); tree check_expr - = CompilePatternCheckExpr::Compile (kase_pattern.get (), + = CompilePatternCheckExpr::Compile (*kase_pattern, match_scrutinee_expr, ctx); tree check_stmt @@ -1106,7 +1207,7 @@ CompileExpr::visit (HIR::CallExpr &expr) { TyTy::BaseType *tyty = nullptr; if (!ctx->get_tyctx ()->lookup_type ( - expr.get_fnexpr ()->get_mappings ().get_hirid (), &tyty)) + expr.get_fnexpr ().get_mappings ().get_hirid (), &tyty)) { rust_error_at (expr.get_locus (), "unknown type"); return; @@ -1132,7 +1233,7 @@ CompileExpr::visit (HIR::CallExpr &expr) { HirId variant_id; bool ok = ctx->get_tyctx ()->lookup_variant_definition ( - expr.get_fnexpr ()->get_mappings ().get_hirid (), &variant_id); + expr.get_fnexpr ().get_mappings ().get_hirid (), &variant_id); rust_assert (ok); ok = adt->lookup_variant_by_id (variant_id, &variant, @@ -1143,10 +1244,10 @@ CompileExpr::visit (HIR::CallExpr &expr) // this assumes all fields are in order from type resolution and if a // base struct was specified those fields are filed via accessors std::vector<tree> arguments; - for (size_t i = 0; i < expr.get_arguments ().size (); i++) + for (size_t i = 0; i < expr.num_params (); i++) { auto &argument = expr.get_arguments ().at (i); - auto rvalue = CompileExpr::Compile (argument.get (), ctx); + auto rvalue = CompileExpr::Compile (*argument, ctx); // assignments are coercion sites so lets convert the rvalue if // necessary @@ -1170,26 +1271,34 @@ CompileExpr::visit (HIR::CallExpr &expr) arguments.push_back (rvalue); } - // the constructor depends on whether this is actually an enum or not if - // its an enum we need to setup the discriminator - std::vector<tree> ctor_arguments; - if (adt->is_enum ()) + if (!adt->is_enum ()) { - HIR::Expr *discrim_expr = variant->get_discriminant (); - tree discrim_expr_node = CompileExpr::Compile (discrim_expr, ctx); - tree folded_discrim_expr = fold_expr (discrim_expr_node); - tree qualifier = folded_discrim_expr; - - ctor_arguments.push_back (qualifier); + translated + = Backend::constructor_expression (compiled_adt_type, + adt->is_enum (), arguments, + union_disriminator, + expr.get_locus ()); + return; } - for (auto &arg : arguments) - ctor_arguments.push_back (arg); - translated - = Backend::constructor_expression (compiled_adt_type, adt->is_enum (), - ctor_arguments, union_disriminator, + HIR::Expr &discrim_expr = variant->get_discriminant (); + tree discrim_expr_node = CompileExpr::Compile (discrim_expr, ctx); + tree folded_discrim_expr = fold_expr (discrim_expr_node); + tree qualifier = folded_discrim_expr; + + tree enum_root_files = TYPE_FIELDS (compiled_adt_type); + tree payload_root = DECL_CHAIN (enum_root_files); + + tree payload + = Backend::constructor_expression (TREE_TYPE (payload_root), true, + {arguments}, union_disriminator, expr.get_locus ()); + std::vector<tree> ctor_arguments = {qualifier, payload}; + translated = Backend::constructor_expression (compiled_adt_type, false, + ctor_arguments, -1, + expr.get_locus ()); + return; } @@ -1209,13 +1318,13 @@ CompileExpr::visit (HIR::CallExpr &expr) } const TyTy::FnType *fn = static_cast<const TyTy::FnType *> (base); - auto param = fn->param_at (index); - *result = param.second; + auto ¶m = fn->param_at (index); + *result = param.get_type (); return true; }; - auto fn_address = CompileExpr::Compile (expr.get_fnexpr ().get (), ctx); + auto fn_address = CompileExpr::Compile (expr.get_fnexpr (), ctx); // is this a closure call? bool possible_trait_call @@ -1242,7 +1351,7 @@ CompileExpr::visit (HIR::CallExpr &expr) for (size_t i = 0; i < expr.get_arguments ().size (); i++) { auto &argument = expr.get_arguments ().at (i); - auto rvalue = CompileExpr::Compile (argument.get (), ctx); + auto rvalue = CompileExpr::Compile (*argument, ctx); if (is_variadic && i >= required_num_args) { @@ -1282,7 +1391,7 @@ void CompileExpr::visit (HIR::MethodCallExpr &expr) { // method receiver - tree self = CompileExpr::Compile (expr.get_receiver ().get (), ctx); + tree self = CompileExpr::Compile (expr.get_receiver (), ctx); // lookup the expected function type TyTy::BaseType *lookup_fntype = nullptr; @@ -1293,8 +1402,8 @@ CompileExpr::visit (HIR::MethodCallExpr &expr) TyTy::FnType *fntype = static_cast<TyTy::FnType *> (lookup_fntype); TyTy::BaseType *receiver = nullptr; - ok = ctx->get_tyctx ()->lookup_receiver (expr.get_mappings ().get_hirid (), - &receiver); + ok = ctx->get_tyctx ()->lookup_type ( + expr.get_receiver ().get_mappings ().get_hirid (), &receiver); rust_assert (ok); bool is_dyn_dispatch @@ -1322,7 +1431,7 @@ CompileExpr::visit (HIR::MethodCallExpr &expr) // lookup the autoderef mappings HirId autoderef_mappings_id - = expr.get_receiver ()->get_mappings ().get_hirid (); + = expr.get_receiver ().get_mappings ().get_hirid (); std::vector<Resolver::Adjustment> *adjustments = nullptr; ok = ctx->get_tyctx ()->lookup_autoderef_mappings (autoderef_mappings_id, &adjustments); @@ -1330,7 +1439,7 @@ CompileExpr::visit (HIR::MethodCallExpr &expr) // apply adjustments for the fn call self = resolve_adjustements (*adjustments, self, - expr.get_receiver ()->get_locus ()); + expr.get_receiver ().get_locus ()); std::vector<tree> args; args.push_back (self); // adjusted self @@ -1339,12 +1448,12 @@ CompileExpr::visit (HIR::MethodCallExpr &expr) for (size_t i = 0; i < expr.get_arguments ().size (); i++) { auto &argument = expr.get_arguments ().at (i); - auto rvalue = CompileExpr::Compile (argument.get (), ctx); + auto rvalue = CompileExpr::Compile (*argument, ctx); // assignments are coercion sites so lets convert the rvalue if // necessary, offset from the already adjusted implicit self bool ok; - TyTy::BaseType *expected = fntype->param_at (i + 1).second; + TyTy::BaseType *expected = fntype->param_at (i + 1).get_type (); TyTy::BaseType *actual = nullptr; ok = ctx->get_tyctx ()->lookup_type ( @@ -1419,10 +1528,10 @@ CompileExpr::get_receiver_from_dyn (const TyTy::DynamicObjectType *dyn, } tree -CompileExpr::resolve_operator_overload (LangItem::Kind lang_item_type, - HIR::OperatorExprMeta expr, tree lhs, - tree rhs, HIR::Expr *lhs_expr, - HIR::Expr *rhs_expr) +CompileExpr::resolve_operator_overload ( + LangItem::Kind lang_item_type, HIR::OperatorExprMeta expr, tree lhs, tree rhs, + HIR::Expr &lhs_expr, tl::optional<std::reference_wrapper<HIR::Expr>> rhs_expr, + HIR::PathIdentSegment specified_segment) { TyTy::FnType *fntype; bool is_op_overload = ctx->get_tyctx ()->lookup_operator_overload ( @@ -1431,8 +1540,8 @@ CompileExpr::resolve_operator_overload (LangItem::Kind lang_item_type, TyTy::BaseType *receiver = nullptr; bool ok - = ctx->get_tyctx ()->lookup_receiver (expr.get_mappings ().get_hirid (), - &receiver); + = ctx->get_tyctx ()->lookup_type (lhs_expr.get_mappings ().get_hirid (), + &receiver); rust_assert (ok); bool is_generic_receiver = receiver->get_kind () == TyTy::TypeKind::PARAM; @@ -1443,7 +1552,10 @@ CompileExpr::resolve_operator_overload (LangItem::Kind lang_item_type, } // lookup compiled functions since it may have already been compiled - HIR::PathIdentSegment segment_name (LangItem::ToString (lang_item_type)); + HIR::PathIdentSegment segment_name + = specified_segment.is_error () + ? HIR::PathIdentSegment (LangItem::ToString (lang_item_type)) + : specified_segment; tree fn_expr = resolve_method_address (fntype, receiver, expr.get_locus ()); // lookup the autoderef mappings @@ -1453,7 +1565,7 @@ CompileExpr::resolve_operator_overload (LangItem::Kind lang_item_type, rust_assert (ok); // apply adjustments for the fn call - tree self = resolve_adjustements (*adjustments, lhs, lhs_expr->get_locus ()); + tree self = resolve_adjustements (*adjustments, lhs, lhs_expr.get_locus ()); std::vector<tree> args; args.push_back (self); // adjusted self @@ -1496,6 +1608,10 @@ CompileExpr::compile_integer_literal (const HIR::LiteralExpr &expr, mpz_init (type_max); get_type_static_bounds (type, type_min, type_max); + if (expr.is_negative ()) + { + mpz_neg (ival, ival); + } if (mpz_cmp (ival, type_min) < 0 || mpz_cmp (ival, type_max) > 0) { rust_error_at (expr.get_locus (), @@ -1520,6 +1636,8 @@ CompileExpr::compile_float_literal (const HIR::LiteralExpr &expr, rust_assert (expr.get_lit_type () == HIR::Literal::FLOAT); const auto literal_value = expr.get_literal (); + tree type = TyTyResolveCompile::compile (ctx, tyty); + mpfr_t fval; if (mpfr_init_set_str (fval, literal_value.as_string ().c_str (), 10, MPFR_RNDN) @@ -1529,12 +1647,44 @@ CompileExpr::compile_float_literal (const HIR::LiteralExpr &expr, return error_mark_node; } - tree type = TyTyResolveCompile::compile (ctx, tyty); - // taken from: // see go/gofrontend/expressions.cc:check_float_type - mpfr_exp_t exp = mpfr_get_exp (fval); - bool real_value_overflow = exp > TYPE_PRECISION (type); + bool real_value_overflow; + + if (mpfr_regular_p (fval) != 0) + { + mpfr_exp_t exp = mpfr_get_exp (fval); + mpfr_exp_t min_exp; + mpfr_exp_t max_exp; + + /* + * By convention, the radix point of the significand is just before the + * first digit (which is always 1 due to normalization), like in the C + * language, but unlike in IEEE 754 (thus, for a given number, the + * exponent values in MPFR and in IEEE 754 differ by 1). + */ + switch (TYPE_PRECISION (type)) + { + case 32: + min_exp = -128 + 1; + max_exp = 127 + 1; + break; + case 64: + min_exp = -1024 + 1; + max_exp = 1023 + 1; + break; + default: + rust_error_at (expr.get_locus (), + "precision of type %<%s%> not supported", + tyty->get_name ().c_str ()); + return error_mark_node; + } + real_value_overflow = exp < min_exp || exp > max_exp; + } + else + { + real_value_overflow = false; + } REAL_VALUE_TYPE r1; real_from_mpfr (&r1, fval, type, GMP_RNDN); @@ -1730,7 +1880,7 @@ CompileExpr::visit (HIR::ArrayExpr &expr) const TyTy::ArrayType &array_tyty = static_cast<const TyTy::ArrayType &> (*tyty); - HIR::ArrayElems &elements = *expr.get_internal_elements (); + HIR::ArrayElems &elements = expr.get_internal_elements (); switch (elements.get_array_expr_type ()) { case HIR::ArrayElems::ArrayExprType::VALUES: { @@ -1759,7 +1909,15 @@ CompileExpr::array_value_expr (location_t expr_locus, size_t i = 0; for (auto &elem : elems.get_values ()) { - tree translated_expr = CompileExpr::Compile (elem.get (), ctx); + tree translated_expr = CompileExpr::Compile (*elem, ctx); + if (translated_expr == error_mark_node) + { + rich_location r (line_table, expr_locus); + r.add_fixit_replace (elem->get_locus (), "not a value"); + rust_error_at (r, ErrorCode::E0423, "expected value"); + return error_mark_node; + } + constructor.push_back (translated_expr); indexes.push_back (i++); } @@ -1786,8 +1944,7 @@ CompileExpr::array_copied_expr (location_t expr_locus, } ctx->push_const_context (); - tree capacity_expr - = CompileExpr::Compile (elems.get_num_copies_expr ().get (), ctx); + tree capacity_expr = CompileExpr::Compile (elems.get_num_copies_expr (), ctx); ctx->pop_const_context (); if (!TREE_CONSTANT (capacity_expr)) @@ -1797,8 +1954,7 @@ CompileExpr::array_copied_expr (location_t expr_locus, } // get the compiled value - tree translated_expr - = CompileExpr::Compile (elems.get_elem_to_copy ().get (), ctx); + tree translated_expr = CompileExpr::Compile (elems.get_elem_to_copy (), ctx); tree max_domain = TYPE_MAX_VALUE (domain); tree min_domain = TYPE_MIN_VALUE (domain); @@ -1816,8 +1972,12 @@ CompileExpr::array_copied_expr (location_t expr_locus, if (ctx->const_context_p ()) { size_t idx = 0; + std::vector<unsigned long> indexes; std::vector<tree> constructor; + + indexes.reserve (len); + constructor.reserve (len); for (unsigned HOST_WIDE_INT i = 0; i < len; i++) { constructor.push_back (translated_expr); @@ -1863,6 +2023,9 @@ HIRCompileBase::resolve_adjustements ( tree e = expression; for (auto &adjustment : adjustments) { + if (e == error_mark_node) + return error_mark_node; + switch (adjustment.get_type ()) { case Resolver::Adjustment::AdjustmentType::ERROR: @@ -2003,8 +2166,8 @@ HIRCompileBase::resolve_unsized_dyn_adjustment ( void CompileExpr::visit (HIR::RangeFromToExpr &expr) { - tree from = CompileExpr::Compile (expr.get_from_expr ().get (), ctx); - tree to = CompileExpr::Compile (expr.get_to_expr ().get (), ctx); + tree from = CompileExpr::Compile (expr.get_from_expr (), ctx); + tree to = CompileExpr::Compile (expr.get_to_expr (), ctx); if (from == error_mark_node || to == error_mark_node) { translated = error_mark_node; @@ -2026,7 +2189,7 @@ CompileExpr::visit (HIR::RangeFromToExpr &expr) void CompileExpr::visit (HIR::RangeFromExpr &expr) { - tree from = CompileExpr::Compile (expr.get_from_expr ().get (), ctx); + tree from = CompileExpr::Compile (expr.get_from_expr (), ctx); if (from == error_mark_node) { translated = error_mark_node; @@ -2048,7 +2211,7 @@ CompileExpr::visit (HIR::RangeFromExpr &expr) void CompileExpr::visit (HIR::RangeToExpr &expr) { - tree to = CompileExpr::Compile (expr.get_to_expr ().get (), ctx); + tree to = CompileExpr::Compile (expr.get_to_expr (), ctx); if (to == error_mark_node) { translated = error_mark_node; @@ -2083,8 +2246,8 @@ CompileExpr::visit (HIR::RangeFullExpr &expr) void CompileExpr::visit (HIR::RangeFromToInclExpr &expr) { - tree from = CompileExpr::Compile (expr.get_from_expr ().get (), ctx); - tree to = CompileExpr::Compile (expr.get_to_expr ().get (), ctx); + tree from = CompileExpr::Compile (expr.get_from_expr (), ctx); + tree to = CompileExpr::Compile (expr.get_to_expr (), ctx); if (from == error_mark_node || to == error_mark_node) { translated = error_mark_node; @@ -2106,9 +2269,8 @@ CompileExpr::visit (HIR::RangeFromToInclExpr &expr) void CompileExpr::visit (HIR::ArrayIndexExpr &expr) { - tree array_reference - = CompileExpr::Compile (expr.get_array_expr ().get (), ctx); - tree index = CompileExpr::Compile (expr.get_index_expr ().get (), ctx); + tree array_reference = CompileExpr::Compile (expr.get_array_expr (), ctx); + tree index = CompileExpr::Compile (expr.get_index_expr (), ctx); // this might be an core::ops::index lang item situation TyTy::FnType *fntype; @@ -2119,8 +2281,8 @@ CompileExpr::visit (HIR::ArrayIndexExpr &expr) auto lang_item_type = LangItem::Kind::INDEX; tree operator_overload_call = resolve_operator_overload (lang_item_type, expr, array_reference, - index, expr.get_array_expr ().get (), - expr.get_index_expr ().get ()); + index, expr.get_array_expr (), + expr.get_index_expr ()); tree actual_type = TREE_TYPE (operator_overload_call); bool can_indirect = TYPE_PTR_P (actual_type) || TYPE_REF_P (actual_type); @@ -2142,7 +2304,7 @@ CompileExpr::visit (HIR::ArrayIndexExpr &expr) // indirection if required TyTy::BaseType *array_expr_ty = nullptr; bool ok = ctx->get_tyctx ()->lookup_type ( - expr.get_array_expr ()->get_mappings ().get_hirid (), &array_expr_ty); + expr.get_array_expr ().get_mappings ().get_hirid (), &array_expr_ty); rust_assert (ok); // do we need to add an indirect reference @@ -2293,7 +2455,7 @@ CompileExpr::generate_closure_function (HIR::ClosureExpr &expr, = Backend::struct_field_expression (args_param_expr, i, closure_param.get_locus ()); - CompilePatternBindings::Compile (closure_param.get_pattern ().get (), + CompilePatternBindings::Compile (closure_param.get_pattern (), compiled_param_var, ctx); i++; } @@ -2305,16 +2467,16 @@ CompileExpr::generate_closure_function (HIR::ClosureExpr &expr, } // lookup locals - HIR::Expr *function_body = expr.get_expr ().get (); + HIR::Expr &function_body = expr.get_expr (); bool is_block_expr - = function_body->get_expression_type () == HIR::Expr::ExprType::Block; + = function_body.get_expression_type () == HIR::Expr::ExprType::Block; if (is_block_expr) { - auto body_mappings = function_body->get_mappings (); + auto body_mappings = function_body.get_mappings (); if (flag_name_resolution_2_0) { - auto nr_ctx + auto &nr_ctx = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); auto candidate = nr_ctx.values.to_rib (body_mappings.get_nodeid ()); @@ -2332,13 +2494,13 @@ CompileExpr::generate_closure_function (HIR::ClosureExpr &expr, } tree enclosing_scope = NULL_TREE; - location_t start_location = function_body->get_locus (); - location_t end_location = function_body->get_locus (); + location_t start_location = function_body.get_locus (); + location_t end_location = function_body.get_locus (); if (is_block_expr) { - HIR::BlockExpr *body = static_cast<HIR::BlockExpr *> (function_body); - start_location = body->get_locus (); - end_location = body->get_end_locus (); + auto &body = static_cast<HIR::BlockExpr &> (function_body); + start_location = body.get_locus (); + end_location = body.get_end_locus (); } tree code_block = Backend::block (fndecl, enclosing_scope, {} /*locals*/, @@ -2363,15 +2525,14 @@ CompileExpr::generate_closure_function (HIR::ClosureExpr &expr, if (is_block_expr) { - HIR::BlockExpr *body = static_cast<HIR::BlockExpr *> (function_body); - compile_function_body (fndecl, *body, tyret); + auto &body = static_cast<HIR::BlockExpr &> (function_body); + compile_function_body (fndecl, body, tyret); } else { tree value = CompileExpr::Compile (function_body, ctx); tree return_expr - = Backend::return_statement (fndecl, value, - function_body->get_locus ()); + = Backend::return_statement (fndecl, value, function_body.get_locus ()); ctx->add_statement (return_expr); } @@ -2458,8 +2619,8 @@ CompileExpr::generate_possible_fn_trait_call (HIR::CallExpr &expr, } // need to apply any autoderef's to the self argument - HIR::Expr *fnexpr = expr.get_fnexpr ().get (); - HirId autoderef_mappings_id = fnexpr->get_mappings ().get_hirid (); + HIR::Expr &fnexpr = expr.get_fnexpr (); + HirId autoderef_mappings_id = fnexpr.get_mappings ().get_hirid (); std::vector<Resolver::Adjustment> *adjustments = nullptr; bool ok = ctx->get_tyctx ()->lookup_autoderef_mappings (autoderef_mappings_id, &adjustments); @@ -2472,7 +2633,7 @@ CompileExpr::generate_possible_fn_trait_call (HIR::CallExpr &expr, std::vector<tree> tuple_arg_vals; for (auto &argument : expr.get_arguments ()) { - auto rvalue = CompileExpr::Compile (argument.get (), ctx); + auto rvalue = CompileExpr::Compile (*argument, ctx); tuple_arg_vals.push_back (rvalue); } diff --git a/gcc/rust/backend/rust-compile-expr.h b/gcc/rust/backend/rust-compile-expr.h index b257da5..65ed4b3 100644 --- a/gcc/rust/backend/rust-compile-expr.h +++ b/gcc/rust/backend/rust-compile-expr.h @@ -28,7 +28,7 @@ namespace Compile { class CompileExpr : private HIRCompileBase, protected HIR::HIRExpressionVisitor { public: - static tree Compile (HIR::Expr *expr, Context *ctx); + static tree Compile (HIR::Expr &expr, Context *ctx); void visit (HIR::TupleIndexExpr &expr) override; void visit (HIR::TupleExpr &expr) override; @@ -68,6 +68,8 @@ public: void visit (HIR::RangeFullExpr &expr) override; void visit (HIR::RangeFromToInclExpr &expr) override; void visit (HIR::ClosureExpr &expr) override; + void visit (HIR::InlineAsm &expr) override; + void visit (HIR::LlvmInlineAsm &expr) override; // TODO void visit (HIR::ErrorPropagationExpr &) override {} @@ -76,8 +78,6 @@ public: // TODO // these need to be sugared in the HIR to if statements and a match void visit (HIR::WhileLetLoopExpr &) override {} - void visit (HIR::IfLetExpr &) override {} - void visit (HIR::IfLetExprConseqElse &) override {} // lets not worry about async yet.... void visit (HIR::AwaitExpr &) override {} @@ -97,10 +97,12 @@ protected: TyTy::BaseType *receiver, TyTy::FnType *fntype, tree receiver_ref, location_t expr_locus); - tree resolve_operator_overload (LangItem::Kind lang_item_type, - HIR::OperatorExprMeta expr, tree lhs, - tree rhs, HIR::Expr *lhs_expr, - HIR::Expr *rhs_expr); + tree resolve_operator_overload ( + LangItem::Kind lang_item_type, HIR::OperatorExprMeta expr, tree lhs, + tree rhs, HIR::Expr &lhs_expr, + tl::optional<std::reference_wrapper<HIR::Expr>> rhs_expr, + HIR::PathIdentSegment specified_segment + = HIR::PathIdentSegment::create_error ()); tree compile_bool_literal (const HIR::LiteralExpr &expr, const TyTy::BaseType *tyty); diff --git a/gcc/rust/backend/rust-compile-extern.h b/gcc/rust/backend/rust-compile-extern.h index bacd1c0..d6aa589 100644 --- a/gcc/rust/backend/rust-compile-extern.h +++ b/gcc/rust/backend/rust-compile-extern.h @@ -34,16 +34,10 @@ class CompileExternItem : public HIRCompileBase, public: static tree compile (HIR::ExternalItem *item, Context *ctx, TyTy::BaseType *concrete = nullptr, - bool is_query_mode = false, location_t ref_locus = UNDEF_LOCATION) { CompileExternItem compiler (ctx, concrete, ref_locus); item->accept_vis (compiler); - - if (is_query_mode && compiler.reference == error_mark_node) - rust_internal_error_at (ref_locus, "failed to compile extern item: %s", - item->as_string ().c_str ()); - return compiler.reference; } diff --git a/gcc/rust/backend/rust-compile-fnparam.cc b/gcc/rust/backend/rust-compile-fnparam.cc index af24ca0..b40065e 100644 --- a/gcc/rust/backend/rust-compile-fnparam.cc +++ b/gcc/rust/backend/rust-compile-fnparam.cc @@ -31,20 +31,20 @@ CompileFnParam::CompileFnParam (Context *ctx, tree fndecl, tree decl_type, {} Bvariable * -CompileFnParam::compile (Context *ctx, tree fndecl, HIR::FunctionParam *param, +CompileFnParam::compile (Context *ctx, tree fndecl, HIR::FunctionParam ¶m, tree decl_type, location_t locus) { CompileFnParam compiler (ctx, fndecl, decl_type, locus); - param->get_param_name ()->accept_vis (compiler); + param.get_param_name ().accept_vis (compiler); return compiler.compiled_param; } Bvariable * -CompileFnParam::compile (Context *ctx, tree fndecl, HIR::Pattern *param, +CompileFnParam::compile (Context *ctx, tree fndecl, HIR::Pattern ¶m, tree decl_type, location_t locus) { CompileFnParam compiler (ctx, fndecl, decl_type, locus); - param->accept_vis (compiler); + param.accept_vis (compiler); return compiler.compiled_param; } @@ -69,24 +69,35 @@ CompileFnParam::visit (HIR::WildcardPattern &pattern) } void +CompileFnParam::visit (HIR::TuplePattern &pattern) +{ + compiled_param = create_tmp_param_var (decl_type); + CompilePatternBindings::Compile ( + pattern, Backend::var_expression (compiled_param, locus), ctx); +} + +void CompileFnParam::visit (HIR::StructPattern &pattern) { - tree tmp_param_var = create_tmp_param_var (decl_type); - CompilePatternBindings::Compile (&pattern, tmp_param_var, ctx); + compiled_param = create_tmp_param_var (decl_type); + CompilePatternBindings::Compile ( + pattern, Backend::var_expression (compiled_param, locus), ctx); } void CompileFnParam::visit (HIR::TupleStructPattern &pattern) { - tree tmp_param_var = create_tmp_param_var (decl_type); - CompilePatternBindings::Compile (&pattern, tmp_param_var, ctx); + compiled_param = create_tmp_param_var (decl_type); + CompilePatternBindings::Compile ( + pattern, Backend::var_expression (compiled_param, locus), ctx); } void CompileFnParam::visit (HIR::ReferencePattern &pattern) { - tree tmp_param_var = create_tmp_param_var (decl_type); - CompilePatternBindings::Compile (&pattern, tmp_param_var, ctx); + compiled_param = create_tmp_param_var (decl_type); + CompilePatternBindings::Compile ( + pattern, Backend::var_expression (compiled_param, locus), ctx); } Bvariable * @@ -102,7 +113,7 @@ CompileSelfParam::compile (Context *ctx, tree fndecl, HIR::SelfParam &self, return Backend::parameter_variable (fndecl, "self", decl_type, locus); } -tree +Bvariable * CompileFnParam::create_tmp_param_var (tree decl_type) { // generate the anon param @@ -110,10 +121,8 @@ CompileFnParam::create_tmp_param_var (tree decl_type) std::string cpp_str_identifier = std::string (IDENTIFIER_POINTER (tmp_ident)); decl_type = Backend::immutable_type (decl_type); - compiled_param = Backend::parameter_variable (fndecl, cpp_str_identifier, - decl_type, locus); - - return Backend::var_expression (compiled_param, locus); + return Backend::parameter_variable (fndecl, cpp_str_identifier, decl_type, + locus); } } // namespace Compile diff --git a/gcc/rust/backend/rust-compile-fnparam.h b/gcc/rust/backend/rust-compile-fnparam.h index 09a3e69..189216c 100644 --- a/gcc/rust/backend/rust-compile-fnparam.h +++ b/gcc/rust/backend/rust-compile-fnparam.h @@ -29,9 +29,9 @@ class CompileFnParam : private HIRCompileBase, protected HIR::HIRPatternVisitor { public: static Bvariable *compile (Context *ctx, tree fndecl, - HIR::FunctionParam *param, tree decl_type, + HIR::FunctionParam ¶m, tree decl_type, location_t locus); - static Bvariable *compile (Context *ctx, tree fndecl, HIR::Pattern *param, + static Bvariable *compile (Context *ctx, tree fndecl, HIR::Pattern ¶m, tree decl_type, location_t locus); void visit (HIR::IdentifierPattern &pattern) override; @@ -47,12 +47,12 @@ public: void visit (HIR::QualifiedPathInExpression &) override {} void visit (HIR::RangePattern &) override {} void visit (HIR::SlicePattern &) override {} - void visit (HIR::TuplePattern &) override {} + void visit (HIR::TuplePattern &) override; private: CompileFnParam (Context *ctx, tree fndecl, tree decl_type, location_t locus); - tree create_tmp_param_var (tree decl_type); + Bvariable *create_tmp_param_var (tree decl_type); tree fndecl; tree decl_type; diff --git a/gcc/rust/backend/rust-compile-implitem.cc b/gcc/rust/backend/rust-compile-implitem.cc index 4c7d8e8..1230c85 100644 --- a/gcc/rust/backend/rust-compile-implitem.cc +++ b/gcc/rust/backend/rust-compile-implitem.cc @@ -27,13 +27,34 @@ CompileTraitItem::visit (HIR::TraitItemConst &constant) rust_assert (concrete != nullptr); TyTy::BaseType *resolved_type = concrete; - auto canonical_path = ctx->get_mappings ().lookup_canonical_path ( - constant.get_mappings ().get_nodeid ()); + tl::optional<Resolver::CanonicalPath> canonical_path; + if (flag_name_resolution_2_0) + { + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); + + canonical_path = nr_ctx.values.to_canonical_path ( + constant.get_mappings ().get_nodeid ()); + } + else + { + canonical_path = ctx->get_mappings ().lookup_canonical_path ( + constant.get_mappings ().get_nodeid ()); + } + + rust_assert (canonical_path); + + HIR::Expr &const_value_expr = constant.get_expr (); + TyTy::BaseType *expr_type = nullptr; + bool ok = ctx->get_tyctx ()->lookup_type ( + const_value_expr.get_mappings ().get_hirid (), &expr_type); + rust_assert (ok); - HIR::Expr *const_value_expr = constant.get_expr ().get (); tree const_expr - = compile_constant_item (resolved_type, *canonical_path, const_value_expr, - constant.get_locus ()); + = compile_constant_item (constant.get_mappings ().get_hirid (), expr_type, + resolved_type, *canonical_path, const_value_expr, + constant.get_locus (), + const_value_expr.get_locus ()); ctx->push_const (const_expr); ctx->insert_const_decl (constant.get_mappings ().get_hirid (), const_expr); @@ -43,7 +64,7 @@ CompileTraitItem::visit (HIR::TraitItemConst &constant) void CompileTraitItem::visit (HIR::TraitItemFunc &func) { - rust_assert (func.has_block_defined ()); + rust_assert (func.has_definition ()); rust_assert (concrete->get_kind () == TyTy::TypeKind::FNDEF); TyTy::FnType *fntype = static_cast<TyTy::FnType *> (concrete); @@ -75,18 +96,32 @@ CompileTraitItem::visit (HIR::TraitItemFunc &func) fntype->override_context (); } - auto canonical_path = ctx->get_mappings ().lookup_canonical_path ( - func.get_mappings ().get_nodeid ()); + tl::optional<Resolver::CanonicalPath> canonical_path; + if (flag_name_resolution_2_0) + { + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); + + canonical_path + = nr_ctx.values.to_canonical_path (func.get_mappings ().get_nodeid ()); + } + else + { + canonical_path = ctx->get_mappings ().lookup_canonical_path ( + func.get_mappings ().get_nodeid ()); + } + + rust_assert (canonical_path); // FIXME: How do we get the proper visibility here? auto vis = HIR::Visibility (HIR::Visibility::VisType::PUBLIC); HIR::TraitFunctionDecl &function = func.get_decl (); tree fndecl - = compile_function (function.get_function_name ().as_string (), + = compile_function (false, function.get_function_name ().as_string (), function.get_self (), function.get_function_params (), function.get_qualifiers (), vis, func.get_outer_attrs (), func.get_locus (), - func.get_block_expr ().get (), *canonical_path, fntype); + &func.get_block_expr (), *canonical_path, fntype); reference = address_expression (fndecl, ref_locus); } diff --git a/gcc/rust/backend/rust-compile-implitem.h b/gcc/rust/backend/rust-compile-implitem.h index d2ef989..2d18dbf 100644 --- a/gcc/rust/backend/rust-compile-implitem.h +++ b/gcc/rust/backend/rust-compile-implitem.h @@ -30,16 +30,10 @@ class CompileInherentImplItem : public CompileItem public: static tree Compile (HIR::ImplItem *item, Context *ctx, TyTy::BaseType *concrete = nullptr, - bool is_query_mode = false, location_t ref_locus = UNDEF_LOCATION) { CompileInherentImplItem compiler (ctx, concrete, ref_locus); item->accept_vis (compiler); - - if (is_query_mode && compiler.reference == error_mark_node) - rust_internal_error_at (ref_locus, "failed to compile impl item: %s", - item->as_string ().c_str ()); - return compiler.reference; } diff --git a/gcc/rust/backend/rust-compile-intrinsic.cc b/gcc/rust/backend/rust-compile-intrinsic.cc index de3bb6e..4888e23 100644 --- a/gcc/rust/backend/rust-compile-intrinsic.cc +++ b/gcc/rust/backend/rust-compile-intrinsic.cc @@ -17,23 +17,19 @@ #include "rust-compile-intrinsic.h" #include "rust-compile-context.h" #include "rust-compile-type.h" -#include "rust-compile-expr.h" #include "rust-compile-fnparam.h" #include "rust-builtins.h" #include "rust-diagnostics.h" #include "rust-location.h" #include "rust-constexpr.h" +#include "rust-session-manager.h" #include "rust-tree.h" #include "tree-core.h" #include "rust-gcc.h" -#include "print-tree.h" #include "fold-const.h" #include "langhooks.h" -#include "rust-gcc.h" #include "rust-constexpr.h" -#include "print-tree.h" - // declaration taken from "stringpool.h" // the get_identifier macro causes compilation issues extern tree @@ -92,6 +88,10 @@ static tree move_val_init_handler (Context *ctx, TyTy::FnType *fntype); static tree assume_handler (Context *ctx, TyTy::FnType *fntype); +static tree +discriminant_value_handler (Context *ctx, TyTy::FnType *fntype); +static tree +variant_count_handler (Context *ctx, TyTy::FnType *fntype); enum class Prefetch { @@ -194,6 +194,17 @@ expect_handler (bool likely) }; } +static tree +try_handler_inner (Context *ctx, TyTy::FnType *fntype, bool is_new_api); + +const static std::function<tree (Context *, TyTy::FnType *)> +try_handler (bool is_new_api) +{ + return [is_new_api] (Context *ctx, TyTy::FnType *fntype) { + return try_handler_inner (ctx, fntype, is_new_api); + }; +} + inline tree sorry_handler (Context *ctx, TyTy::FnType *fntype) { @@ -205,43 +216,46 @@ sorry_handler (Context *ctx, TyTy::FnType *fntype) static const std::map<std::string, std::function<tree (Context *, TyTy::FnType *)>> - generic_intrinsics = { - {"offset", offset_handler}, - {"size_of", sizeof_handler}, - {"transmute", transmute_handler}, - {"rotate_left", rotate_left_handler}, - {"rotate_right", rotate_right_handler}, - {"wrapping_add", wrapping_op_handler (PLUS_EXPR)}, - {"wrapping_sub", wrapping_op_handler (MINUS_EXPR)}, - {"wrapping_mul", wrapping_op_handler (MULT_EXPR)}, - {"add_with_overflow", op_with_overflow (PLUS_EXPR)}, - {"sub_with_overflow", op_with_overflow (MINUS_EXPR)}, - {"mul_with_overflow", op_with_overflow (MULT_EXPR)}, - {"copy", copy_handler (true)}, - {"copy_nonoverlapping", copy_handler (false)}, - {"prefetch_read_data", prefetch_read_data}, - {"prefetch_write_data", prefetch_write_data}, - {"atomic_store_seqcst", atomic_store_handler (__ATOMIC_SEQ_CST)}, - {"atomic_store_release", atomic_store_handler (__ATOMIC_RELEASE)}, - {"atomic_store_relaxed", atomic_store_handler (__ATOMIC_RELAXED)}, - {"atomic_store_unordered", atomic_store_handler (__ATOMIC_RELAXED)}, - {"atomic_load_seqcst", atomic_load_handler (__ATOMIC_SEQ_CST)}, - {"atomic_load_acquire", atomic_load_handler (__ATOMIC_ACQUIRE)}, - {"atomic_load_relaxed", atomic_load_handler (__ATOMIC_RELAXED)}, - {"atomic_load_unordered", atomic_load_handler (__ATOMIC_RELAXED)}, - {"unchecked_add", unchecked_op_handler (PLUS_EXPR)}, - {"unchecked_sub", unchecked_op_handler (MINUS_EXPR)}, - {"unchecked_mul", unchecked_op_handler (MULT_EXPR)}, - {"unchecked_div", unchecked_op_handler (TRUNC_DIV_EXPR)}, - {"unchecked_rem", unchecked_op_handler (TRUNC_MOD_EXPR)}, - {"unchecked_shl", unchecked_op_handler (LSHIFT_EXPR)}, - {"unchecked_shr", unchecked_op_handler (RSHIFT_EXPR)}, - {"uninit", uninit_handler}, - {"move_val_init", move_val_init_handler}, - {"likely", expect_handler (true)}, - {"unlikely", expect_handler (false)}, - {"assume", assume_handler}, -}; + generic_intrinsics + = {{"offset", offset_handler}, + {"size_of", sizeof_handler}, + {"transmute", transmute_handler}, + {"rotate_left", rotate_left_handler}, + {"rotate_right", rotate_right_handler}, + {"wrapping_add", wrapping_op_handler (PLUS_EXPR)}, + {"wrapping_sub", wrapping_op_handler (MINUS_EXPR)}, + {"wrapping_mul", wrapping_op_handler (MULT_EXPR)}, + {"add_with_overflow", op_with_overflow (PLUS_EXPR)}, + {"sub_with_overflow", op_with_overflow (MINUS_EXPR)}, + {"mul_with_overflow", op_with_overflow (MULT_EXPR)}, + {"copy", copy_handler (true)}, + {"copy_nonoverlapping", copy_handler (false)}, + {"prefetch_read_data", prefetch_read_data}, + {"prefetch_write_data", prefetch_write_data}, + {"atomic_store_seqcst", atomic_store_handler (__ATOMIC_SEQ_CST)}, + {"atomic_store_release", atomic_store_handler (__ATOMIC_RELEASE)}, + {"atomic_store_relaxed", atomic_store_handler (__ATOMIC_RELAXED)}, + {"atomic_store_unordered", atomic_store_handler (__ATOMIC_RELAXED)}, + {"atomic_load_seqcst", atomic_load_handler (__ATOMIC_SEQ_CST)}, + {"atomic_load_acquire", atomic_load_handler (__ATOMIC_ACQUIRE)}, + {"atomic_load_relaxed", atomic_load_handler (__ATOMIC_RELAXED)}, + {"atomic_load_unordered", atomic_load_handler (__ATOMIC_RELAXED)}, + {"unchecked_add", unchecked_op_handler (PLUS_EXPR)}, + {"unchecked_sub", unchecked_op_handler (MINUS_EXPR)}, + {"unchecked_mul", unchecked_op_handler (MULT_EXPR)}, + {"unchecked_div", unchecked_op_handler (TRUNC_DIV_EXPR)}, + {"unchecked_rem", unchecked_op_handler (TRUNC_MOD_EXPR)}, + {"unchecked_shl", unchecked_op_handler (LSHIFT_EXPR)}, + {"unchecked_shr", unchecked_op_handler (RSHIFT_EXPR)}, + {"uninit", uninit_handler}, + {"move_val_init", move_val_init_handler}, + {"likely", expect_handler (true)}, + {"unlikely", expect_handler (false)}, + {"assume", assume_handler}, + {"try", try_handler (false)}, + {"catch_unwind", try_handler (true)}, + {"discriminant_value", discriminant_value_handler}, + {"variant_count", variant_count_handler}}; Intrinsics::Intrinsics (Context *ctx) : ctx (ctx) {} @@ -315,11 +329,11 @@ compile_fn_params (Context *ctx, TyTy::FnType *fntype, tree fndecl, { for (auto &parm : fntype->get_params ()) { - auto &referenced_param = parm.first; - auto ¶m_tyty = parm.second; + auto &referenced_param = parm.get_pattern (); + auto param_tyty = parm.get_type (); auto compiled_param_type = TyTyResolveCompile::compile (ctx, param_tyty); - location_t param_locus = referenced_param->get_locus (); + location_t param_locus = referenced_param.get_locus (); Bvariable *compiled_param_var = CompileFnParam::compile (ctx, fndecl, referenced_param, compiled_param_type, param_locus); @@ -496,9 +510,10 @@ transmute_handler (Context *ctx, TyTy::FnType *fntype) rust_error_at (fntype->get_locus (), "cannot transmute between types of different sizes, or " "dependently-sized types"); - rust_inform (fntype->get_ident ().locus, "source type: %qs (%lu bits)", - fntype->get_params ().at (0).second->as_string ().c_str (), - (unsigned long) source_size); + rust_inform ( + fntype->get_ident ().locus, "source type: %qs (%lu bits)", + fntype->get_params ().at (0).get_type ()->as_string ().c_str (), + (unsigned long) source_size); rust_inform (fntype->get_ident ().locus, "target type: %qs (%lu bits)", fntype->get_return_type ()->as_string ().c_str (), (unsigned long) target_size); @@ -1226,7 +1241,7 @@ assume_handler (Context *ctx, TyTy::FnType *fntype) // TODO: make sure this is actually helping the compiler optimize rust_assert (fntype->get_params ().size () == 1); - rust_assert (fntype->param_at (0).second->get_kind () + rust_assert (fntype->param_at (0).get_type ()->get_kind () == TyTy::TypeKind::BOOL); tree lookup = NULL_TREE; @@ -1258,7 +1273,217 @@ assume_handler (Context *ctx, TyTy::FnType *fntype) TREE_SIDE_EFFECTS (assume_expr) = 1; ctx->add_statement (assume_expr); - // BUILTIN size_of FN BODY END + // BUILTIN assume FN BODY END + + finalize_intrinsic_block (ctx, fndecl); + + return fndecl; +} + +static tree +try_handler_inner (Context *ctx, TyTy::FnType *fntype, bool is_new_api) +{ + rust_assert (fntype->get_params ().size () == 3); + + tree lookup = NULL_TREE; + if (check_for_cached_intrinsic (ctx, fntype, &lookup)) + return lookup; + auto fndecl = compile_intrinsic_function (ctx, fntype); + + enter_intrinsic_block (ctx, fndecl); + + // The following tricks are needed to make sure the try-catch blocks are not + // optimized away + TREE_READONLY (fndecl) = 0; + DECL_DISREGARD_INLINE_LIMITS (fndecl) = 1; + DECL_ATTRIBUTES (fndecl) = tree_cons (get_identifier ("always_inline"), + NULL_TREE, DECL_ATTRIBUTES (fndecl)); + + // BUILTIN try_handler FN BODY BEGIN + // setup the params + std::vector<Bvariable *> param_vars; + compile_fn_params (ctx, fntype, fndecl, ¶m_vars); + if (!Backend::function_set_parameters (fndecl, param_vars)) + return error_mark_node; + tree enclosing_scope = NULL_TREE; + + bool panic_is_abort = Session::get_instance ().options.get_panic_strategy () + == CompileOptions::PanicStrategy::Abort; + tree try_fn = Backend::var_expression (param_vars[0], UNDEF_LOCATION); + tree user_data = Backend::var_expression (param_vars[1], UNDEF_LOCATION); + tree catch_fn = Backend::var_expression (param_vars[2], UNDEF_LOCATION); + tree normal_return_stmt = NULL_TREE; + tree error_return_stmt = NULL_TREE; + tree try_call = Backend::call_expression (try_fn, {user_data}, nullptr, + BUILTINS_LOCATION); + tree catch_call = NULL_TREE; + tree try_block = Backend::block (fndecl, enclosing_scope, {}, UNDEF_LOCATION, + UNDEF_LOCATION); + + if (is_new_api) + { + auto ret_type = TyTyResolveCompile::get_unit_type (ctx); + auto ret_expr = Backend::constructor_expression (ret_type, false, {}, -1, + UNDEF_LOCATION); + normal_return_stmt + = Backend::return_statement (fndecl, ret_expr, BUILTINS_LOCATION); + error_return_stmt + = Backend::return_statement (fndecl, ret_expr, BUILTINS_LOCATION); + } + else + { + normal_return_stmt = Backend::return_statement (fndecl, integer_zero_node, + BUILTINS_LOCATION); + error_return_stmt = Backend::return_statement (fndecl, integer_one_node, + BUILTINS_LOCATION); + } + Backend::block_add_statements (try_block, + std::vector<tree>{try_call, + normal_return_stmt}); + if (panic_is_abort) + { + // skip building the try-catch construct + ctx->add_statement (try_block); + finalize_intrinsic_block (ctx, fndecl); + return fndecl; + } + + tree eh_pointer + = build_call_expr (builtin_decl_explicit (BUILT_IN_EH_POINTER), 1, + integer_zero_node); + catch_call = Backend::call_expression (catch_fn, {user_data, eh_pointer}, + NULL_TREE, BUILTINS_LOCATION); + + tree catch_block = Backend::block (fndecl, enclosing_scope, {}, + UNDEF_LOCATION, UNDEF_LOCATION); + Backend::block_add_statements (catch_block, + std::vector<tree>{catch_call, + error_return_stmt}); + // emulate what cc1plus is doing for C++ try-catch + tree inner_eh_construct + = Backend::exception_handler_statement (catch_call, NULL_TREE, + error_return_stmt, + BUILTINS_LOCATION); + // TODO(liushuyu): eh_personality needs to be implemented as a runtime thing + auto eh_construct + = Backend::exception_handler_statement (try_block, inner_eh_construct, + NULL_TREE, BUILTINS_LOCATION); + ctx->add_statement (eh_construct); + // BUILTIN try_handler FN BODY END + finalize_intrinsic_block (ctx, fndecl); + + return fndecl; +} + +static tree +discriminant_value_handler (Context *ctx, TyTy::FnType *fntype) +{ + rust_assert (fntype->get_params ().size () == 1); + rust_assert (fntype->get_return_type ()->is<TyTy::PlaceholderType> ()); + rust_assert (fntype->has_substitutions ()); + rust_assert (fntype->get_num_type_params () == 1); + auto &mapping = fntype->get_substs ().at (0); + auto param_ty = mapping.get_param_ty (); + rust_assert (param_ty->can_resolve ()); + auto resolved = param_ty->resolve (); + auto p = static_cast<TyTy::PlaceholderType *> (fntype->get_return_type ()); + + TyTy::BaseType *return_type = nullptr; + bool ok = ctx->get_tyctx ()->lookup_builtin ("isize", &return_type); + rust_assert (ok); + + bool is_adt = resolved->is<TyTy::ADTType> (); + bool is_enum = false; + if (is_adt) + { + const auto &adt = *static_cast<TyTy::ADTType *> (resolved); + return_type = adt.get_repr_options ().repr; + rust_assert (return_type != nullptr); + is_enum = adt.is_enum (); + } + + p->set_associated_type (return_type->get_ref ()); + + tree lookup = NULL_TREE; + if (check_for_cached_intrinsic (ctx, fntype, &lookup)) + return lookup; + + auto fndecl = compile_intrinsic_function (ctx, fntype); + + std::vector<Bvariable *> param_vars; + compile_fn_params (ctx, fntype, fndecl, ¶m_vars); + + if (!Backend::function_set_parameters (fndecl, param_vars)) + return error_mark_node; + + enter_intrinsic_block (ctx, fndecl); + + // BUILTIN disriminant_value FN BODY BEGIN + + tree result = integer_zero_node; + if (is_enum) + { + tree val = Backend::var_expression (param_vars[0], UNDEF_LOCATION); + tree deref = build_fold_indirect_ref_loc (UNKNOWN_LOCATION, val); + result = Backend::struct_field_expression (deref, 0, UNKNOWN_LOCATION); + } + + auto return_statement + = Backend::return_statement (fndecl, result, BUILTINS_LOCATION); + ctx->add_statement (return_statement); + + // BUILTIN disriminant_value FN BODY END + + finalize_intrinsic_block (ctx, fndecl); + + return fndecl; +} + +static tree +variant_count_handler (Context *ctx, TyTy::FnType *fntype) +{ + rust_assert (fntype->get_num_type_params () == 1); + auto &mapping = fntype->get_substs ().at (0); + auto param_ty = mapping.get_param_ty (); + rust_assert (param_ty->can_resolve ()); + auto resolved = param_ty->resolve (); + + size_t variant_count = 0; + bool is_adt = resolved->is<TyTy::ADTType> (); + if (is_adt) + { + const auto &adt = *static_cast<TyTy::ADTType *> (resolved); + variant_count = adt.number_of_variants (); + } + + tree lookup = NULL_TREE; + if (check_for_cached_intrinsic (ctx, fntype, &lookup)) + return lookup; + + auto fndecl = compile_intrinsic_function (ctx, fntype); + + std::vector<Bvariable *> param_vars; + compile_fn_params (ctx, fntype, fndecl, ¶m_vars); + + if (!Backend::function_set_parameters (fndecl, param_vars)) + return error_mark_node; + + enter_intrinsic_block (ctx, fndecl); + + // BUILTIN disriminant_value FN BODY BEGIN + tree result_decl = DECL_RESULT (fndecl); + tree type = TREE_TYPE (result_decl); + + mpz_t ival; + mpz_init_set_ui (ival, variant_count); + tree result = wide_int_to_tree (type, wi::from_mpz (type, ival, true)); + mpz_clear (ival); + + auto return_statement + = Backend::return_statement (fndecl, result, BUILTINS_LOCATION); + ctx->add_statement (return_statement); + + // BUILTIN disriminant_value FN BODY END finalize_intrinsic_block (ctx, fndecl); diff --git a/gcc/rust/backend/rust-compile-item.cc b/gcc/rust/backend/rust-compile-item.cc index c0cac68..9666990 100644 --- a/gcc/rust/backend/rust-compile-item.cc +++ b/gcc/rust/backend/rust-compile-item.cc @@ -19,6 +19,8 @@ #include "rust-compile-item.h" #include "rust-compile-implitem.h" #include "rust-compile-extern.h" +#include "rust-substitution-mapper.h" +#include "rust-type-util.h" #include "rust-immutable-name-resolution-context.h" namespace Rust { @@ -35,20 +37,42 @@ CompileItem::visit (HIR::StaticItem &var) return; } + HIR::Expr &const_value_expr = var.get_expr (); + TyTy::BaseType *resolved_type = nullptr; + TyTy::BaseType *expr_type = nullptr; bool ok = ctx->get_tyctx ()->lookup_type (var.get_mappings ().get_hirid (), &resolved_type); rust_assert (ok); + ok = ctx->get_tyctx ()->lookup_type ( + const_value_expr.get_mappings ().get_hirid (), &expr_type); + rust_assert (ok); tree type = TyTyResolveCompile::compile (ctx, resolved_type); - auto canonical_path = ctx->get_mappings ().lookup_canonical_path ( - var.get_mappings ().get_nodeid ()); + tl::optional<Resolver::CanonicalPath> canonical_path; + + if (flag_name_resolution_2_0) + { + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); + + canonical_path + = nr_ctx.values.to_canonical_path (var.get_mappings ().get_nodeid ()); + } + else + { + canonical_path = ctx->get_mappings ().lookup_canonical_path ( + var.get_mappings ().get_nodeid ()); + } + + rust_assert (canonical_path.has_value ()); - HIR::Expr *const_value_expr = var.get_expr ().get (); ctx->push_const_context (); - tree value = compile_constant_item (resolved_type, *canonical_path, - const_value_expr, var.get_locus ()); + tree value + = compile_constant_item (var.get_mappings ().get_hirid (), expr_type, + resolved_type, *canonical_path, const_value_expr, + var.get_locus (), const_value_expr.get_locus ()); ctx->pop_const_context (); std::string name = canonical_path->get (); @@ -74,16 +98,21 @@ CompileItem::visit (HIR::StaticItem &var) void CompileItem::visit (HIR::ConstantItem &constant) { + HIR::Expr &const_value_expr = constant.get_expr (); auto &mappings = constant.get_mappings (); if (ctx->lookup_const_decl (mappings.get_hirid (), &reference)) return; // resolve the type - TyTy::BaseType *resolved_type = nullptr; + TyTy::BaseType *constant_type = nullptr; + TyTy::BaseType *expr_type = nullptr; bool ok - = ctx->get_tyctx ()->lookup_type (mappings.get_hirid (), &resolved_type); + = ctx->get_tyctx ()->lookup_type (mappings.get_hirid (), &constant_type); + rust_assert (ok); + ok = ctx->get_tyctx ()->lookup_type ( + const_value_expr.get_mappings ().get_hirid (), &expr_type); rust_assert (ok); // canonical path @@ -92,7 +121,7 @@ CompileItem::visit (HIR::ConstantItem &constant) if (flag_name_resolution_2_0) { - auto nr_ctx + auto &nr_ctx = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); canonical_path @@ -105,11 +134,12 @@ CompileItem::visit (HIR::ConstantItem &constant) .value (); } - HIR::Expr *const_value_expr = constant.get_expr ().get (); ctx->push_const_context (); tree const_expr - = compile_constant_item (resolved_type, canonical_path, const_value_expr, - constant.get_locus ()); + = compile_constant_item (mappings.get_hirid (), expr_type, constant_type, + canonical_path, const_value_expr, + constant.get_locus (), + const_value_expr.get_locus ()); ctx->pop_const_context (); ctx->push_const (const_expr); @@ -137,12 +167,33 @@ CompileItem::visit (HIR::Function &function) // is given if (concrete == nullptr) return; - else + + rust_assert (concrete->get_kind () == TyTy::TypeKind::FNDEF); + TyTy::FnType *concrete_fnty = static_cast<TyTy::FnType *> (concrete); + bool is_trait_item_concrete + = ctx->get_mappings () + .lookup_trait_item_defid (concrete_fnty->get_id ()) + .has_value (); + if (!is_trait_item_concrete) { rust_assert (concrete->get_kind () == TyTy::TypeKind::FNDEF); fntype = static_cast<TyTy::FnType *> (concrete); - fntype->monomorphize (); } + else + { + TyTy::BaseType *infer + = Resolver::SubstMapper::InferSubst (fntype, function.get_locus ()); + TyTy::BaseType *resolved + = Resolver::unify_site (function.get_mappings ().get_hirid (), + TyTy::TyWithLocation (infer), + TyTy::TyWithLocation (concrete), + function.get_locus ()); + + rust_assert (resolved->is<TyTy::FnType> ()); + fntype = resolved->as<TyTy::FnType> (); + } + + fntype->monomorphize (); } else { @@ -164,7 +215,7 @@ CompileItem::visit (HIR::Function &function) if (flag_name_resolution_2_0) { - auto nr_ctx + auto &nr_ctx = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); auto path = nr_ctx.values.to_canonical_path ( @@ -201,14 +252,17 @@ CompileItem::visit (HIR::Function &function) if (function.get_qualifiers ().is_const ()) ctx->push_const_context (); + auto lookup_root_item = ctx->get_mappings ().lookup_hir_item ( + function.get_mappings ().get_hirid ()); + bool is_root_item = lookup_root_item.has_value (); tree fndecl - = compile_function (function.get_function_name ().as_string (), + = compile_function (is_root_item, + function.get_function_name ().as_string (), function.get_self_param (), function.get_function_params (), function.get_qualifiers (), function.get_visibility (), function.get_outer_attrs (), function.get_locus (), - function.get_definition ().get (), canonical_path, - fntype); + &function.get_definition (), canonical_path, fntype); reference = address_expression (fndecl, ref_locus); if (function.get_qualifiers ().is_const ()) @@ -220,7 +274,7 @@ CompileItem::visit (HIR::ImplBlock &impl_block) { TyTy::BaseType *self_lookup = nullptr; if (!ctx->get_tyctx ()->lookup_type ( - impl_block.get_type ()->get_mappings ().get_hirid (), &self_lookup)) + impl_block.get_type ().get_mappings ().get_hirid (), &self_lookup)) { rust_error_at (impl_block.get_locus (), "failed to resolve type of impl"); return; diff --git a/gcc/rust/backend/rust-compile-item.h b/gcc/rust/backend/rust-compile-item.h index efc65fe..d9d946d 100644 --- a/gcc/rust/backend/rust-compile-item.h +++ b/gcc/rust/backend/rust-compile-item.h @@ -31,16 +31,10 @@ protected: public: static tree compile (HIR::Item *item, Context *ctx, TyTy::BaseType *concrete = nullptr, - bool is_query_mode = false, location_t ref_locus = UNDEF_LOCATION) { CompileItem compiler (ctx, concrete, ref_locus); item->accept_vis (compiler); - - if (is_query_mode && compiler.reference == error_mark_node) - rust_internal_error_at (ref_locus, "failed to compile item: %s", - item->as_string ().c_str ()); - return compiler.reference; } diff --git a/gcc/rust/backend/rust-compile-pattern.cc b/gcc/rust/backend/rust-compile-pattern.cc index ffa1fa7..e83717b 100644 --- a/gcc/rust/backend/rust-compile-pattern.cc +++ b/gcc/rust/backend/rust-compile-pattern.cc @@ -21,6 +21,7 @@ #include "rust-compile-resolve-path.h" #include "rust-constexpr.h" #include "rust-compile-type.h" +#include "print-tree.h" namespace Rust { namespace Compile { @@ -57,17 +58,14 @@ CompilePatternCheckExpr::visit (HIR::PathInExpression &pattern) rust_assert (ok); // find discriminant field of scrutinee - tree scrutinee_record_expr - = Backend::struct_field_expression (match_scrutinee_expr, 0, - pattern.get_locus ()); tree scrutinee_expr_qualifier_expr - = Backend::struct_field_expression (scrutinee_record_expr, 0, + = Backend::struct_field_expression (match_scrutinee_expr, 0, pattern.get_locus ()); // must be enum match_scrutinee_expr = scrutinee_expr_qualifier_expr; - HIR::Expr *discrim_expr = variant->get_discriminant (); + HIR::Expr &discrim_expr = variant->get_discriminant (); tree discrim_expr_node = CompileExpr::Compile (discrim_expr, ctx); check_expr @@ -80,10 +78,9 @@ void CompilePatternCheckExpr::visit (HIR::LiteralPattern &pattern) { // Compile the literal - HIR::LiteralExpr *litexpr - = new HIR::LiteralExpr (pattern.get_mappings (), pattern.get_literal (), - pattern.get_locus (), - std::vector<AST::Attribute> ()); + auto litexpr = std::make_unique<HIR::LiteralExpr> ( + HIR::LiteralExpr (pattern.get_mappings (), pattern.get_literal (), + pattern.get_locus (), std::vector<AST::Attribute> ())); // Note: Floating point literals are currently accepted but will likely be // forbidden in LiteralPatterns in a future version of Rust. @@ -95,7 +92,7 @@ CompilePatternCheckExpr::visit (HIR::LiteralPattern &pattern) rust_sorry_at (pattern.get_locus (), "floating-point literal in pattern"); } - tree lit = CompileExpr::Compile (litexpr, ctx); + tree lit = CompileExpr::Compile (*litexpr, ctx); check_expr = Backend::comparison_expression (ComparisonOperator::EQUAL, match_scrutinee_expr, lit, @@ -103,19 +100,17 @@ CompilePatternCheckExpr::visit (HIR::LiteralPattern &pattern) } static tree -compile_range_pattern_bound (HIR::RangePatternBound *bound, +compile_range_pattern_bound (HIR::RangePatternBound &bound, Analysis::NodeMapping mappings, location_t locus, Context *ctx) { tree result = NULL_TREE; - switch (bound->get_bound_type ()) + switch (bound.get_bound_type ()) { case HIR::RangePatternBound::RangePatternBoundType::LITERAL: { - HIR::RangePatternBoundLiteral &ref - = *static_cast<HIR::RangePatternBoundLiteral *> (bound); + auto &ref = static_cast<HIR::RangePatternBoundLiteral &> (bound); - HIR::LiteralExpr *litexpr - = new HIR::LiteralExpr (mappings, ref.get_literal (), locus, + HIR::LiteralExpr litexpr (mappings, ref.get_literal (), locus, std::vector<AST::Attribute> ()); result = CompileExpr::Compile (litexpr, ctx); @@ -123,8 +118,7 @@ compile_range_pattern_bound (HIR::RangePatternBound *bound, break; case HIR::RangePatternBound::RangePatternBoundType::PATH: { - HIR::RangePatternBoundPath &ref - = *static_cast<HIR::RangePatternBoundPath *> (bound); + auto &ref = static_cast<HIR::RangePatternBoundPath &> (bound); result = ResolvePathRef::Compile (ref.get_path (), ctx); @@ -134,8 +128,7 @@ compile_range_pattern_bound (HIR::RangePatternBound *bound, break; case HIR::RangePatternBound::RangePatternBoundType::QUALPATH: { - HIR::RangePatternBoundQualPath &ref - = *static_cast<HIR::RangePatternBoundQualPath *> (bound); + auto &ref = static_cast<HIR::RangePatternBoundQualPath &> (bound); result = ResolvePathRef::Compile (ref.get_qualified_path (), ctx); @@ -150,10 +143,10 @@ compile_range_pattern_bound (HIR::RangePatternBound *bound, void CompilePatternCheckExpr::visit (HIR::RangePattern &pattern) { - tree upper = compile_range_pattern_bound (pattern.get_upper_bound ().get (), + tree upper = compile_range_pattern_bound (pattern.get_upper_bound (), pattern.get_mappings (), pattern.get_locus (), ctx); - tree lower = compile_range_pattern_bound (pattern.get_lower_bound ().get (), + tree lower = compile_range_pattern_bound (pattern.get_lower_bound (), pattern.get_mappings (), pattern.get_locus (), ctx); @@ -175,7 +168,7 @@ CompilePatternCheckExpr::visit (HIR::ReferencePattern &pattern) { match_scrutinee_expr = indirect_expression (match_scrutinee_expr, pattern.get_locus ()); - pattern.get_referenced_pattern ()->accept_vis (*this); + pattern.get_referenced_pattern ().accept_vis (*this); } void @@ -183,14 +176,13 @@ CompilePatternCheckExpr::visit (HIR::AltPattern &pattern) { auto &alts = pattern.get_alts (); - check_expr = CompilePatternCheckExpr::Compile (alts.at (0).get (), + check_expr = CompilePatternCheckExpr::Compile (*alts.at (0), match_scrutinee_expr, ctx); auto end = alts.end (); for (auto i = alts.begin () + 1; i != end; i++) { tree next_expr - = CompilePatternCheckExpr::Compile (i->get (), match_scrutinee_expr, - ctx); + = CompilePatternCheckExpr::Compile (**i, match_scrutinee_expr, ctx); check_expr = Backend::arithmetic_or_logical_expression ( ArithmeticOrLogicalOperator::BITWISE_OR, check_expr, next_expr, (*i)->get_locus ()); @@ -229,15 +221,12 @@ CompilePatternCheckExpr::visit (HIR::StructPattern &pattern) // // would be DECL_QUALIFIER i think. For now this will just access the // // first record field and its respective qualifier because it will // // always be set because this is all a big special union - HIR::Expr *discrim_expr = variant->get_discriminant (); + HIR::Expr &discrim_expr = variant->get_discriminant (); tree discrim_expr_node = CompileExpr::Compile (discrim_expr, ctx); // find discriminant field of scrutinee - tree scrutinee_record_expr - = Backend::struct_field_expression (match_scrutinee_expr, variant_index, - pattern.get_path ().get_locus ()); tree scrutinee_expr_qualifier_expr - = Backend::struct_field_expression (scrutinee_record_expr, 0, + = Backend::struct_field_expression (match_scrutinee_expr, 0, pattern.get_path ().get_locus ()); check_expr @@ -246,7 +235,7 @@ CompilePatternCheckExpr::visit (HIR::StructPattern &pattern) discrim_expr_node, pattern.get_path ().get_locus ()); - match_scrutinee_expr = scrutinee_record_expr; + match_scrutinee_expr = scrutinee_expr_qualifier_expr; } else { @@ -282,11 +271,11 @@ CompilePatternCheckExpr::visit (HIR::StructPattern &pattern) ident.get_locus ()); tree check_expr_sub - = CompilePatternCheckExpr::Compile (ident.get_pattern ().get (), + = CompilePatternCheckExpr::Compile (ident.get_pattern (), field_expr, ctx); check_expr = Backend::arithmetic_or_logical_expression ( ArithmeticOrLogicalOperator::BITWISE_AND, check_expr, - check_expr_sub, ident.get_pattern ()->get_locus ()); + check_expr_sub, ident.get_pattern ().get_locus ()); } break; @@ -301,8 +290,6 @@ CompilePatternCheckExpr::visit (HIR::StructPattern &pattern) void CompilePatternCheckExpr::visit (HIR::TupleStructPattern &pattern) { - size_t tuple_field_index; - // lookup the type TyTy::BaseType *lookup = nullptr; bool ok = ctx->get_tyctx ()->lookup_type ( @@ -313,6 +300,7 @@ CompilePatternCheckExpr::visit (HIR::TupleStructPattern &pattern) rust_assert (lookup->get_kind () == TyTy::TypeKind::ADT); TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (lookup); + int variant_index = 0; rust_assert (adt->number_of_variants () > 0); TyTy::VariantDef *variant = nullptr; if (adt->is_enum ()) @@ -323,20 +311,16 @@ CompilePatternCheckExpr::visit (HIR::TupleStructPattern &pattern) pattern.get_path ().get_mappings ().get_hirid (), &variant_id); rust_assert (ok); - int variant_index = 0; ok = adt->lookup_variant_by_id (variant_id, &variant, &variant_index); rust_assert (ok); // find expected discriminant - HIR::Expr *discrim_expr = variant->get_discriminant (); + HIR::Expr &discrim_expr = variant->get_discriminant (); tree discrim_expr_node = CompileExpr::Compile (discrim_expr, ctx); // find discriminant field of scrutinee - tree scrutinee_record_expr - = Backend::struct_field_expression (match_scrutinee_expr, variant_index, - pattern.get_path ().get_locus ()); tree scrutinee_expr_qualifier_expr - = Backend::struct_field_expression (scrutinee_record_expr, 0, + = Backend::struct_field_expression (match_scrutinee_expr, 0, pattern.get_path ().get_locus ()); check_expr @@ -344,21 +328,15 @@ CompilePatternCheckExpr::visit (HIR::TupleStructPattern &pattern) scrutinee_expr_qualifier_expr, discrim_expr_node, pattern.get_path ().get_locus ()); - - match_scrutinee_expr = scrutinee_record_expr; - // we are offsetting by + 1 here since the first field in the record - // is always the discriminator - tuple_field_index = 1; } else { variant = adt->get_variants ().at (0); check_expr = boolean_true_node; - tuple_field_index = 0; } - std::unique_ptr<HIR::TupleStructItems> &items = pattern.get_items (); - switch (items->get_item_type ()) + HIR::TupleStructItems &items = pattern.get_items (); + switch (items.get_item_type ()) { case HIR::TupleStructItems::RANGED: { // TODO @@ -368,21 +346,30 @@ CompilePatternCheckExpr::visit (HIR::TupleStructPattern &pattern) case HIR::TupleStructItems::MULTIPLE: { HIR::TupleStructItemsNoRange &items_no_range - = static_cast<HIR::TupleStructItemsNoRange &> (*items.get ()); + = static_cast<HIR::TupleStructItemsNoRange &> (items); rust_assert (items_no_range.get_patterns ().size () == variant->num_fields ()); + size_t tuple_field_index = 0; for (auto &pattern : items_no_range.get_patterns ()) { + // find payload union field of scrutinee + tree payload_ref + = Backend::struct_field_expression (match_scrutinee_expr, 1, + pattern->get_locus ()); + + tree variant_ref + = Backend::struct_field_expression (payload_ref, variant_index, + pattern->get_locus ()); + tree field_expr - = Backend::struct_field_expression (match_scrutinee_expr, + = Backend::struct_field_expression (variant_ref, tuple_field_index++, pattern->get_locus ()); tree check_expr_sub - = CompilePatternCheckExpr::Compile (pattern.get (), field_expr, - ctx); + = CompilePatternCheckExpr::Compile (*pattern, field_expr, ctx); check_expr = Backend::arithmetic_or_logical_expression ( ArithmeticOrLogicalOperator::BITWISE_AND, check_expr, check_expr_sub, pattern->get_locus ()); @@ -397,7 +384,7 @@ CompilePatternCheckExpr::visit (HIR::TuplePattern &pattern) { check_expr = boolean_true_node; - switch (pattern.get_items ()->get_item_type ()) + switch (pattern.get_items ().get_item_type ()) { case HIR::TuplePatternItems::RANGED: { // TODO @@ -407,7 +394,7 @@ CompilePatternCheckExpr::visit (HIR::TuplePattern &pattern) case HIR::TuplePatternItems::MULTIPLE: { auto &items = static_cast<HIR::TuplePatternItemsMultiple &> ( - *pattern.get_items ()); + pattern.get_items ()); size_t tuple_field_index = 0; for (auto &pat : items.get_patterns ()) @@ -418,7 +405,7 @@ CompilePatternCheckExpr::visit (HIR::TuplePattern &pattern) pat->get_locus ()); tree check_expr_sub - = CompilePatternCheckExpr::Compile (pat.get (), field_expr, ctx); + = CompilePatternCheckExpr::Compile (*pat, field_expr, ctx); check_expr = Backend::arithmetic_or_logical_expression ( ArithmeticOrLogicalOperator::BITWISE_AND, check_expr, check_expr_sub, pat->get_locus ()); @@ -459,8 +446,8 @@ CompilePatternBindings::visit (HIR::TupleStructPattern &pattern) rust_assert (variant->get_variant_type () == TyTy::VariantDef::VariantType::TUPLE); - std::unique_ptr<HIR::TupleStructItems> &items = pattern.get_items (); - switch (items->get_item_type ()) + HIR::TupleStructItems &items = pattern.get_items (); + switch (items.get_item_type ()) { case HIR::TupleStructItems::RANGED: { // TODO @@ -470,20 +457,22 @@ CompilePatternBindings::visit (HIR::TupleStructPattern &pattern) case HIR::TupleStructItems::MULTIPLE: { HIR::TupleStructItemsNoRange &items_no_range - = static_cast<HIR::TupleStructItemsNoRange &> (*items.get ()); + = static_cast<HIR::TupleStructItemsNoRange &> (items); rust_assert (items_no_range.get_patterns ().size () == variant->num_fields ()); if (adt->is_enum ()) { - // we are offsetting by + 1 here since the first field in the record - // is always the discriminator - size_t tuple_field_index = 1; + size_t tuple_field_index = 0; for (auto &pattern : items_no_range.get_patterns ()) { + tree payload_accessor_union + = Backend::struct_field_expression (match_scrutinee_expr, 1, + pattern->get_locus ()); + tree variant_accessor - = Backend::struct_field_expression (match_scrutinee_expr, + = Backend::struct_field_expression (payload_accessor_union, variant_index, pattern->get_locus ()); @@ -492,8 +481,7 @@ CompilePatternBindings::visit (HIR::TupleStructPattern &pattern) tuple_field_index++, pattern->get_locus ()); - ctx->insert_pattern_binding ( - pattern->get_mappings ().get_hirid (), binding); + CompilePatternBindings::Compile (*pattern, binding, ctx); } } else @@ -508,8 +496,7 @@ CompilePatternBindings::visit (HIR::TupleStructPattern &pattern) tuple_field_index++, pattern->get_locus ()); - ctx->insert_pattern_binding ( - pattern->get_mappings ().get_hirid (), binding); + CompilePatternBindings::Compile (*pattern, binding, ctx); } } } @@ -576,16 +563,18 @@ CompilePatternBindings::visit (HIR::StructPattern &pattern) tree binding = error_mark_node; if (adt->is_enum ()) { + tree payload_accessor_union + = Backend::struct_field_expression (match_scrutinee_expr, 1, + ident.get_locus ()); + tree variant_accessor - = Backend::struct_field_expression (match_scrutinee_expr, + = Backend::struct_field_expression (payload_accessor_union, variant_index, ident.get_locus ()); - // we are offsetting by + 1 here since the first field in the - // record is always the discriminator - binding = Backend::struct_field_expression (variant_accessor, - offs + 1, - ident.get_locus ()); + binding + = Backend::struct_field_expression (variant_accessor, offs, + ident.get_locus ()); } else { @@ -609,17 +598,111 @@ CompilePatternBindings::visit (HIR::ReferencePattern &pattern) tree derefed = indirect_expression (match_scrutinee_expr, pattern.get_locus ()); - CompilePatternBindings::Compile (pattern.get_referenced_pattern ().get (), - derefed, ctx); + CompilePatternBindings::Compile (pattern.get_referenced_pattern (), derefed, + ctx); } void CompilePatternBindings::visit (HIR::IdentifierPattern &pattern) { - ctx->insert_pattern_binding (pattern.get_mappings ().get_hirid (), - match_scrutinee_expr); + if (!pattern.get_is_ref ()) + { + ctx->insert_pattern_binding (pattern.get_mappings ().get_hirid (), + match_scrutinee_expr); + return; + } + + tree ref = address_expression (match_scrutinee_expr, + EXPR_LOCATION (match_scrutinee_expr)); + ctx->insert_pattern_binding (pattern.get_mappings ().get_hirid (), ref); +} + +void +CompilePatternBindings::visit (HIR::TuplePattern &pattern) +{ + rust_assert (pattern.has_tuple_pattern_items ()); + + // lookup the type + TyTy::BaseType *ty = nullptr; + bool ok + = ctx->get_tyctx ()->lookup_type (pattern.get_mappings ().get_hirid (), + &ty); + rust_assert (ok); + + switch (pattern.get_items ().get_item_type ()) + { + case HIR::TuplePatternItems::ItemType::RANGED: { + size_t tuple_idx = 0; + auto &items + = static_cast<HIR::TuplePatternItemsRanged &> (pattern.get_items ()); + + auto &items_lower = items.get_lower_patterns (); + auto &items_upper = items.get_upper_patterns (); + + for (auto &sub : items_lower) + { + TyTy::BaseType *ty_sub = nullptr; + HirId sub_id = sub->get_mappings ().get_hirid (); + bool ok = ctx->get_tyctx ()->lookup_type (sub_id, &ty_sub); + rust_assert (ok); + + tree sub_init + = Backend::struct_field_expression (match_scrutinee_expr, + tuple_idx, sub->get_locus ()); + + CompilePatternBindings::Compile (*sub.get (), sub_init, ctx); + tuple_idx++; + } + + rust_assert (ty->get_kind () == TyTy::TypeKind::TUPLE); + tuple_idx = static_cast<TyTy::TupleType &> (*ty).num_fields () + - items_upper.size (); + + for (auto &sub : items_upper) + { + TyTy::BaseType *ty_sub = nullptr; + HirId sub_id = sub->get_mappings ().get_hirid (); + bool ok = ctx->get_tyctx ()->lookup_type (sub_id, &ty_sub); + rust_assert (ok); + + tree sub_init + = Backend::struct_field_expression (match_scrutinee_expr, + tuple_idx, sub->get_locus ()); + CompilePatternBindings::Compile (*sub.get (), sub_init, ctx); + tuple_idx++; + } + + return; + } + case HIR::TuplePatternItems::ItemType::MULTIPLE: { + size_t tuple_idx = 0; + auto &items = static_cast<HIR::TuplePatternItemsMultiple &> ( + pattern.get_items ()); + + for (auto &sub : items.get_patterns ()) + { + TyTy::BaseType *ty_sub = nullptr; + HirId sub_id = sub->get_mappings ().get_hirid (); + bool ok = ctx->get_tyctx ()->lookup_type (sub_id, &ty_sub); + rust_assert (ok); + + tree sub_init + = Backend::struct_field_expression (match_scrutinee_expr, + tuple_idx, sub->get_locus ()); + CompilePatternBindings::Compile (*sub.get (), sub_init, ctx); + tuple_idx++; + } + + return; + } + default: { + rust_unreachable (); + } + } } +// + void CompilePatternLet::visit (HIR::IdentifierPattern &pattern) { @@ -670,12 +753,12 @@ CompilePatternLet::visit (HIR::TuplePattern &pattern) tree access_expr = Backend::var_expression (tmp_var, pattern.get_locus ()); ctx->add_statement (init_stmt); - switch (pattern.get_items ()->get_item_type ()) + switch (pattern.get_items ().get_item_type ()) { case HIR::TuplePatternItems::ItemType::RANGED: { size_t tuple_idx = 0; auto &items - = static_cast<HIR::TuplePatternItemsRanged &> (*pattern.get_items ()); + = static_cast<HIR::TuplePatternItemsRanged &> (pattern.get_items ()); auto &items_lower = items.get_lower_patterns (); auto &items_upper = items.get_upper_patterns (); @@ -719,7 +802,7 @@ CompilePatternLet::visit (HIR::TuplePattern &pattern) case HIR::TuplePatternItems::ItemType::MULTIPLE: { size_t tuple_idx = 0; auto &items = static_cast<HIR::TuplePatternItemsMultiple &> ( - *pattern.get_items ()); + pattern.get_items ()); for (auto &sub : items.get_patterns ()) { diff --git a/gcc/rust/backend/rust-compile-pattern.h b/gcc/rust/backend/rust-compile-pattern.h index 521ed0d..c7a62fc 100644 --- a/gcc/rust/backend/rust-compile-pattern.h +++ b/gcc/rust/backend/rust-compile-pattern.h @@ -26,11 +26,11 @@ class CompilePatternCheckExpr : public HIRCompileBase, public HIR::HIRPatternVisitor { public: - static tree Compile (HIR::Pattern *pattern, tree match_scrutinee_expr, + static tree Compile (HIR::Pattern &pattern, tree match_scrutinee_expr, Context *ctx) { CompilePatternCheckExpr compiler (ctx, match_scrutinee_expr); - pattern->accept_vis (compiler); + pattern.accept_vis (compiler); rust_assert (compiler.check_expr); return compiler.check_expr; } @@ -71,17 +71,18 @@ class CompilePatternBindings : public HIRCompileBase, public HIR::HIRPatternVisitor { public: - static void Compile (HIR::Pattern *pattern, tree match_scrutinee_expr, + static void Compile (HIR::Pattern &pattern, tree match_scrutinee_expr, Context *ctx) { CompilePatternBindings compiler (ctx, match_scrutinee_expr); - pattern->accept_vis (compiler); + pattern.accept_vis (compiler); } void visit (HIR::StructPattern &pattern) override; void visit (HIR::TupleStructPattern &pattern) override; void visit (HIR::ReferencePattern &pattern) override; void visit (HIR::IdentifierPattern &) override; + void visit (HIR::TuplePattern &pattern) override; // Empty visit for unused Pattern HIR nodes. void visit (HIR::AltPattern &) override {} @@ -90,7 +91,6 @@ public: void visit (HIR::QualifiedPathInExpression &) override {} void visit (HIR::RangePattern &) override {} void visit (HIR::SlicePattern &) override {} - void visit (HIR::TuplePattern &) override {} void visit (HIR::WildcardPattern &) override {} protected: diff --git a/gcc/rust/backend/rust-compile-resolve-path.cc b/gcc/rust/backend/rust-compile-resolve-path.cc index 7c9b303..81d2dbb 100644 --- a/gcc/rust/backend/rust-compile-resolve-path.cc +++ b/gcc/rust/backend/rust-compile-resolve-path.cc @@ -32,18 +32,41 @@ namespace Rust { namespace Compile { -void -ResolvePathRef::visit (HIR::QualifiedPathInExpression &expr) +tree +ResolvePathRef::Compile (HIR::QualifiedPathInExpression &expr, Context *ctx) { - resolved = resolve (expr.get_final_segment ().get_segment (), - expr.get_mappings (), expr.get_locus (), true); + ResolvePathRef resolver (ctx); + return resolver.resolve_path_like (expr); } -void -ResolvePathRef::visit (HIR::PathInExpression &expr) +tree +ResolvePathRef::Compile (HIR::PathInExpression &expr, Context *ctx) { - resolved = resolve (expr.get_final_segment ().get_segment (), - expr.get_mappings (), expr.get_locus (), false); + ResolvePathRef resolver (ctx); + return resolver.resolve_path_like (expr); +} + +ResolvePathRef::ResolvePathRef (Context *ctx) : HIRCompileBase (ctx) {} + +template <typename T> +tree +ResolvePathRef::resolve_path_like (T &expr) +{ + if (expr.is_lang_item ()) + { + auto lang_item + = Analysis::Mappings::get ().get_lang_item_node (expr.get_lang_item ()); + + // FIXME: Is that correct? :/ + auto final_segment + = HIR::PathIdentSegment (LangItem::ToString (expr.get_lang_item ())); + + return resolve_with_node_id (final_segment, expr.get_mappings (), + expr.get_locus (), true, lang_item); + } + + return resolve (expr.get_final_segment ().get_segment (), + expr.get_mappings (), expr.get_locus (), true); } tree @@ -81,52 +104,30 @@ ResolvePathRef::attempt_constructor_expression_lookup ( tree compiled_adt_type = TyTyResolveCompile::compile (ctx, adt); // make the ctor for the union - HIR::Expr *discrim_expr = variant->get_discriminant (); + HIR::Expr &discrim_expr = variant->get_discriminant (); + ctx->push_const_context (); tree discrim_expr_node = CompileExpr::Compile (discrim_expr, ctx); + ctx->pop_const_context (); tree folded_discrim_expr = fold_expr (discrim_expr_node); tree qualifier = folded_discrim_expr; - return Backend::constructor_expression (compiled_adt_type, true, {qualifier}, - union_disriminator, expr_locus); + // false for is enum but this is an enum but we have a new layout + return Backend::constructor_expression (compiled_adt_type, false, {qualifier}, + -1, expr_locus); } tree -ResolvePathRef::resolve (const HIR::PathIdentSegment &final_segment, - const Analysis::NodeMapping &mappings, - location_t expr_locus, bool is_qualified_path) +ResolvePathRef::resolve_with_node_id ( + const HIR::PathIdentSegment &final_segment, + const Analysis::NodeMapping &mappings, location_t expr_locus, + bool is_qualified_path, NodeId resolved_node_id) { TyTy::BaseType *lookup = nullptr; bool ok = ctx->get_tyctx ()->lookup_type (mappings.get_hirid (), &lookup); rust_assert (ok); - // need to look up the reference for this identifier - - // this can fail because it might be a Constructor for something - // in that case the caller should attempt ResolvePathType::Compile - NodeId ref_node_id = UNKNOWN_NODEID; - if (flag_name_resolution_2_0) - { - auto nr_ctx - = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - - auto resolved = nr_ctx.lookup (mappings.get_nodeid ()); - - if (!resolved) - return attempt_constructor_expression_lookup (lookup, ctx, mappings, - expr_locus); - - ref_node_id = *resolved; - } - else - { - if (!ctx->get_resolver ()->lookup_resolved_name (mappings.get_nodeid (), - &ref_node_id)) - return attempt_constructor_expression_lookup (lookup, ctx, mappings, - expr_locus); - } - tl::optional<HirId> hid - = ctx->get_mappings ().lookup_node_to_hir (ref_node_id); + = ctx->get_mappings ().lookup_node_to_hir (resolved_node_id); if (!hid.has_value ()) { rust_error_at (expr_locus, "reverse call path lookup failure"); @@ -185,6 +186,11 @@ ResolvePathRef::resolve (const HIR::PathIdentSegment &final_segment, } } + // Handle unit struct + if (lookup->get_kind () == TyTy::TypeKind::ADT) + return attempt_constructor_expression_lookup (lookup, ctx, mappings, + expr_locus); + // let the query system figure it out tree resolved_item = query_compile (ref, lookup, final_segment, mappings, expr_locus, is_qualified_path); @@ -192,10 +198,50 @@ ResolvePathRef::resolve (const HIR::PathIdentSegment &final_segment, { TREE_USED (resolved_item) = 1; } + return resolved_item; } tree +ResolvePathRef::resolve (const HIR::PathIdentSegment &final_segment, + const Analysis::NodeMapping &mappings, + location_t expr_locus, bool is_qualified_path) +{ + TyTy::BaseType *lookup = nullptr; + bool ok = ctx->get_tyctx ()->lookup_type (mappings.get_hirid (), &lookup); + rust_assert (ok); + + // need to look up the reference for this identifier + + // this can fail because it might be a Constructor for something + // in that case the caller should attempt ResolvePathType::Compile + NodeId ref_node_id = UNKNOWN_NODEID; + if (flag_name_resolution_2_0) + { + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); + + auto resolved = nr_ctx.lookup (mappings.get_nodeid ()); + + if (!resolved) + return attempt_constructor_expression_lookup (lookup, ctx, mappings, + expr_locus); + + ref_node_id = *resolved; + } + else + { + if (!ctx->get_resolver ()->lookup_resolved_name (mappings.get_nodeid (), + &ref_node_id)) + return attempt_constructor_expression_lookup (lookup, ctx, mappings, + expr_locus); + } + + return resolve_with_node_id (final_segment, mappings, expr_locus, + is_qualified_path, ref_node_id); +} + +tree HIRCompileBase::query_compile (HirId ref, TyTy::BaseType *lookup, const HIR::PathIdentSegment &final_segment, const Analysis::NodeMapping &mappings, @@ -205,11 +251,9 @@ HIRCompileBase::query_compile (HirId ref, TyTy::BaseType *lookup, if (auto resolved_item = ctx->get_mappings ().lookup_hir_item (ref)) { if (!lookup->has_substitutions_defined ()) - return CompileItem::compile (*resolved_item, ctx, nullptr, true, - expr_locus); + return CompileItem::compile (*resolved_item, ctx, nullptr, expr_locus); else - return CompileItem::compile (*resolved_item, ctx, lookup, true, - expr_locus); + return CompileItem::compile (*resolved_item, ctx, lookup, expr_locus); } else if (auto hir_extern_item = ctx->get_mappings ().lookup_hir_extern_item (ref)) @@ -217,10 +261,10 @@ HIRCompileBase::query_compile (HirId ref, TyTy::BaseType *lookup, HIR::ExternalItem *resolved_extern_item = hir_extern_item->first; if (!lookup->has_substitutions_defined ()) return CompileExternItem::compile (resolved_extern_item, ctx, nullptr, - true, expr_locus); + expr_locus); else return CompileExternItem::compile (resolved_extern_item, ctx, lookup, - true, expr_locus); + expr_locus); } else { @@ -242,17 +286,14 @@ HIRCompileBase::query_compile (HirId ref, TyTy::BaseType *lookup, { if (!lookup->has_substitutions_defined ()) return CompileInherentImplItem::Compile (resolved_item->first, ctx, - nullptr, true, expr_locus); + nullptr, expr_locus); else return CompileInherentImplItem::Compile (resolved_item->first, ctx, - lookup, true, expr_locus); + lookup, expr_locus); } - else + else if (auto trait_item + = ctx->get_mappings ().lookup_hir_trait_item (ref)) { - // it might be resolved to a trait item - tl::optional<HIR::TraitItem *> trait_item - = ctx->get_mappings ().lookup_hir_trait_item (ref); - HIR::Trait *trait = ctx->get_mappings ().lookup_trait_item_mapping ( trait_item.value ()->get_mappings ().get_hirid ()); @@ -262,16 +303,41 @@ HIRCompileBase::query_compile (HirId ref, TyTy::BaseType *lookup, trait->get_mappings ().get_defid (), &trait_ref); rust_assert (ok); - TyTy::BaseType *receiver = nullptr; - ok = ctx->get_tyctx ()->lookup_receiver (mappings.get_hirid (), - &receiver); - rust_assert (ok); - receiver = receiver->destructure (); + if (trait_item.value ()->get_item_kind () + == HIR::TraitItem::TraitItemKind::CONST) + { + auto &c + = *static_cast<HIR::TraitItemConst *> (trait_item.value ()); + if (!c.has_expr ()) + { + rich_location r (line_table, expr_locus); + r.add_range (trait->get_locus ()); + r.add_range (c.get_locus ()); + rust_error_at (r, "no default expression on trait constant"); + return error_mark_node; + } + + return CompileExpr::Compile (c.get_expr (), ctx); + } + + if (trait_item.value ()->get_item_kind () + != HIR::TraitItem::TraitItemKind::FUNC) + return error_mark_node; // the type resolver can only resolve type bounds to their trait // item so its up to us to figure out if this path should resolve // to an trait-impl-block-item or if it can be defaulted to the // trait-impl-item's definition + // + // because we know this is resolved to a trait item we can actually + // just grab the Self type parameter here for the receiver to match + // the appropriate impl block + + rust_assert (lookup->is<TyTy::FnType> ()); + auto fn = lookup->as<TyTy::FnType> (); + rust_assert (fn->get_num_type_params () > 0); + auto &self = fn->get_substs ().at (0); + auto receiver = self.get_param_ty (); auto candidates = Resolver::PathProbeImplTrait::Probe (receiver, final_segment, trait_ref); @@ -301,16 +367,15 @@ HIRCompileBase::query_compile (HirId ref, TyTy::BaseType *lookup, TyTy::BaseType *self = nullptr; bool ok = ctx->get_tyctx ()->lookup_type ( - impl->get_type ()->get_mappings ().get_hirid (), &self); + impl->get_type ().get_mappings ().get_hirid (), &self); rust_assert (ok); if (!lookup->has_substitutions_defined ()) return CompileInherentImplItem::Compile (impl_item, ctx, - nullptr, true, - expr_locus); + nullptr, expr_locus); else return CompileInherentImplItem::Compile (impl_item, ctx, lookup, - true, expr_locus); + expr_locus); } } } diff --git a/gcc/rust/backend/rust-compile-resolve-path.h b/gcc/rust/backend/rust-compile-resolve-path.h index 7654fd9..79bfb86 100644 --- a/gcc/rust/backend/rust-compile-resolve-path.h +++ b/gcc/rust/backend/rust-compile-resolve-path.h @@ -20,53 +20,39 @@ #define RUST_COMPILE_RESOLVE_PATH #include "rust-compile-base.h" -#include "rust-hir-visitor.h" namespace Rust { namespace Compile { -class ResolvePathRef : public HIRCompileBase, public HIR::HIRPatternVisitor +class ResolvePathRef : public HIRCompileBase { public: - static tree Compile (HIR::QualifiedPathInExpression &expr, Context *ctx) - { - ResolvePathRef resolver (ctx); - expr.accept_vis (resolver); - return resolver.resolved; - } - - static tree Compile (HIR::PathInExpression &expr, Context *ctx) - { - ResolvePathRef resolver (ctx); - expr.accept_vis (resolver); - return resolver.resolved; - } - - void visit (HIR::PathInExpression &expr) override; - void visit (HIR::QualifiedPathInExpression &expr) override; - - // Empty visit for unused Pattern HIR nodes. - void visit (HIR::IdentifierPattern &) override {} - void visit (HIR::LiteralPattern &) override {} - void visit (HIR::RangePattern &) override {} - void visit (HIR::ReferencePattern &) override {} - void visit (HIR::SlicePattern &) override {} - void visit (HIR::AltPattern &) override {} - void visit (HIR::StructPattern &) override {} - void visit (HIR::TuplePattern &) override {} - void visit (HIR::TupleStructPattern &) override {} - void visit (HIR::WildcardPattern &) override {} - - ResolvePathRef (Context *ctx) - : HIRCompileBase (ctx), resolved (error_mark_node) - {} - + static tree Compile (HIR::QualifiedPathInExpression &expr, Context *ctx); + + static tree Compile (HIR::PathInExpression &expr, Context *ctx); + + ResolvePathRef (Context *ctx); + + /** + * Generic visitor for both PathInExpression and QualifiedPathInExpression + */ + template <typename T> tree resolve_path_like (T &expr); + + /** + * Inner implementation of `resolve` - resolution with an already known NodeId + */ + tree resolve_with_node_id (const HIR::PathIdentSegment &final_segment, + const Analysis::NodeMapping &mappings, + location_t locus, bool is_qualified_path, + NodeId resolved_node_id); + /** + * Resolve a mappings' NodeId and call into `resolve_with_node_id` which + * performs the rest of the path resolution + */ tree resolve (const HIR::PathIdentSegment &final_segment, const Analysis::NodeMapping &mappings, location_t locus, bool is_qualified_path); - tree resolved; - private: tree attempt_constructor_expression_lookup (TyTy::BaseType *lookup, Context *ctx, diff --git a/gcc/rust/backend/rust-compile-stmt.cc b/gcc/rust/backend/rust-compile-stmt.cc index d8b27ff..a4b5a98 100644 --- a/gcc/rust/backend/rust-compile-stmt.cc +++ b/gcc/rust/backend/rust-compile-stmt.cc @@ -40,13 +40,13 @@ CompileStmt::Compile (HIR::Stmt *stmt, Context *ctx) void CompileStmt::visit (HIR::ExprStmt &stmt) { - translated = CompileExpr::Compile (stmt.get_expr ().get (), ctx); + translated = CompileExpr::Compile (stmt.get_expr (), ctx); } void CompileStmt::visit (HIR::LetStmt &stmt) { - HIR::Pattern &stmt_pattern = *stmt.get_pattern (); + HIR::Pattern &stmt_pattern = stmt.get_pattern (); HirId stmt_id = stmt_pattern.get_mappings ().get_hirid (); TyTy::BaseType *ty = nullptr; @@ -68,7 +68,7 @@ CompileStmt::visit (HIR::LetStmt &stmt) if (!stmt.has_init_expr ()) return; - tree init = CompileExpr::Compile (stmt.get_init_expr ().get (), ctx); + tree init = CompileExpr::Compile (stmt.get_init_expr (), ctx); // FIXME use error_mark_node, check that CompileExpr returns error_mark_node // on failure and make this an assertion if (init == nullptr) @@ -76,11 +76,11 @@ CompileStmt::visit (HIR::LetStmt &stmt) TyTy::BaseType *actual = nullptr; bool ok = ctx->get_tyctx ()->lookup_type ( - stmt.get_init_expr ()->get_mappings ().get_hirid (), &actual); + stmt.get_init_expr ().get_mappings ().get_hirid (), &actual); rust_assert (ok); - location_t lvalue_locus = stmt.get_pattern ()->get_locus (); - location_t rvalue_locus = stmt.get_init_expr ()->get_locus (); + location_t lvalue_locus = stmt.get_pattern ().get_locus (); + location_t rvalue_locus = stmt.get_init_expr ().get_locus (); TyTy::BaseType *expected = ty; init = coercion_site (stmt.get_mappings ().get_hirid (), init, actual, expected, lvalue_locus, rvalue_locus); diff --git a/gcc/rust/backend/rust-compile-struct-field-expr.cc b/gcc/rust/backend/rust-compile-struct-field-expr.cc index 4a3b26c..0ac25e7 100644 --- a/gcc/rust/backend/rust-compile-struct-field-expr.cc +++ b/gcc/rust/backend/rust-compile-struct-field-expr.cc @@ -27,22 +27,22 @@ CompileStructExprField::CompileStructExprField (Context *ctx) {} tree -CompileStructExprField::Compile (HIR::StructExprField *field, Context *ctx) +CompileStructExprField::Compile (HIR::StructExprField &field, Context *ctx) { CompileStructExprField compiler (ctx); - switch (field->get_kind ()) + switch (field.get_kind ()) { case HIR::StructExprField::StructExprFieldKind::IDENTIFIER: - compiler.visit (static_cast<HIR::StructExprFieldIdentifier &> (*field)); + compiler.visit (static_cast<HIR::StructExprFieldIdentifier &> (field)); break; case HIR::StructExprField::StructExprFieldKind::IDENTIFIER_VALUE: compiler.visit ( - static_cast<HIR::StructExprFieldIdentifierValue &> (*field)); + static_cast<HIR::StructExprFieldIdentifierValue &> (field)); break; case HIR::StructExprField::StructExprFieldKind::INDEX_VALUE: - compiler.visit (static_cast<HIR::StructExprFieldIndexValue &> (*field)); + compiler.visit (static_cast<HIR::StructExprFieldIndexValue &> (field)); break; } return compiler.translated; @@ -51,13 +51,13 @@ CompileStructExprField::Compile (HIR::StructExprField *field, Context *ctx) void CompileStructExprField::visit (HIR::StructExprFieldIdentifierValue &field) { - translated = CompileExpr::Compile (field.get_value ().get (), ctx); + translated = CompileExpr::Compile (field.get_value (), ctx); } void CompileStructExprField::visit (HIR::StructExprFieldIndexValue &field) { - translated = CompileExpr::Compile (field.get_value ().get (), ctx); + translated = CompileExpr::Compile (field.get_value (), ctx); } void @@ -74,7 +74,7 @@ CompileStructExprField::visit (HIR::StructExprFieldIdentifier &field) HIR::GenericArgs::create_empty ()); HIR::PathInExpression expr (mappings_copy2, {seg}, field.get_locus (), false, {}); - translated = CompileExpr::Compile (&expr, ctx); + translated = CompileExpr::Compile (expr, ctx); } } // namespace Compile diff --git a/gcc/rust/backend/rust-compile-struct-field-expr.h b/gcc/rust/backend/rust-compile-struct-field-expr.h index f1d7055..055019c 100644 --- a/gcc/rust/backend/rust-compile-struct-field-expr.h +++ b/gcc/rust/backend/rust-compile-struct-field-expr.h @@ -27,7 +27,7 @@ namespace Compile { class CompileStructExprField : private HIRCompileBase { public: - static tree Compile (HIR::StructExprField *field, Context *ctx); + static tree Compile (HIR::StructExprField &field, Context *ctx); protected: void visit (HIR::StructExprFieldIdentifierValue &field); diff --git a/gcc/rust/backend/rust-compile-type.cc b/gcc/rust/backend/rust-compile-type.cc index b546a05..83e5756 100644 --- a/gcc/rust/backend/rust-compile-type.cc +++ b/gcc/rust/backend/rust-compile-type.cc @@ -22,6 +22,7 @@ #include "rust-gcc.h" #include "tree.h" +#include "stor-layout.h" namespace Rust { namespace Compile { @@ -54,7 +55,7 @@ TyTyResolveCompile::compile (Context *ctx, const TyTy::BaseType *ty, // see: gcc/c/c-decl.cc:8230-8241 // https://github.com/Rust-GCC/gccrs/blob/0024bc2f028369b871a65ceb11b2fddfb0f9c3aa/gcc/c/c-decl.c#L8229-L8241 tree -TyTyResolveCompile::get_implicit_enumeral_node_type () +TyTyResolveCompile::get_implicit_enumeral_node_type (TyTy::BaseType *repr) { // static tree enum_node = NULL_TREE; // if (enum_node == NULL_TREE) @@ -76,25 +77,26 @@ TyTyResolveCompile::get_implicit_enumeral_node_type () // } // return enum_node; - static tree enum_node = NULL_TREE; - if (enum_node == NULL_TREE) - { - // equivalent to isize - enum_node = Backend::named_type ( - "enumeral", Backend::integer_type (false, Backend::get_pointer_size ()), - BUILTINS_LOCATION); - } - return enum_node; + return compile (ctx, repr); } tree -TyTyResolveCompile::get_unit_type () +TyTyResolveCompile::get_unit_type (Context *ctx) { static tree unit_type; if (unit_type == nullptr) { + auto cn = ctx->get_mappings ().get_current_crate (); + auto &c = ctx->get_mappings ().get_ast_crate (cn); + location_t locus = BUILTINS_LOCATION; + if (c.items.size () > 0) + { + auto &item = c.items[0]; + locus = item->get_locus (); + } + auto unit_type_node = Backend::struct_type ({}); - unit_type = Backend::named_type ("()", unit_type_node, BUILTINS_LOCATION); + unit_type = Backend::named_type ("()", unit_type_node, locus); } return unit_type; } @@ -208,12 +210,12 @@ TyTyResolveCompile::visit (const TyTy::FnType &type) for (auto ¶m_pair : type.get_params ()) { - auto param_tyty = param_pair.second; + auto param_tyty = param_pair.get_type (); auto compiled_param_type = TyTyResolveCompile::compile (ctx, param_tyty, trait_object_mode); auto compiled_param = Backend::typed_identifier ( - param_pair.first->as_string (), compiled_param_type, + param_pair.get_pattern ().as_string (), compiled_param_type, ctx->get_mappings ().lookup_location (param_tyty->get_ref ())); parameters.push_back (compiled_param); @@ -268,8 +270,8 @@ TyTyResolveCompile::visit (const TyTy::ADTType &type) fields.push_back (std::move (f)); } - type_record = type.is_union () ? Backend::union_type (fields) - : Backend::struct_type (fields); + type_record = type.is_union () ? Backend::union_type (fields, false) + : Backend::struct_type (fields, false); } else { @@ -297,21 +299,39 @@ TyTyResolveCompile::visit (const TyTy::ADTType &type) // Ada, qual_union_types might still work for this but I am not 100% sure. // I ran into some issues lets reuse our normal union and ask Ada people // about it. + // + // I think the above is actually wrong and it should actually be this + // + // struct { + // int RUST$ENUM$DISR; // take into account the repr for this TODO + // union { + // // Variant A + // struct { + // // No additional fields + // } A; + + // // Variant B + // struct { + // // No additional fields + // } B; + + // // Variant C + // struct { + // char c; + // } C; + + // // Variant D + // struct { + // int64_t x; + // int64_t y; + // } D; + // } payload; // The union of all variant data + // }; std::vector<tree> variant_records; for (auto &variant : type.get_variants ()) { std::vector<Backend::typed_identifier> fields; - - // add in the qualifier field for the variant - tree enumeral_type - = TyTyResolveCompile::get_implicit_enumeral_node_type (); - Backend::typed_identifier f (RUST_ENUM_DISR_FIELD_NAME, enumeral_type, - ctx->get_mappings ().lookup_location ( - variant->get_id ())); - fields.push_back (std::move (f)); - - // compile the rest of the fields for (size_t i = 0; i < variant->num_fields (); i++) { const TyTy::StructFieldType *field @@ -335,9 +355,6 @@ TyTyResolveCompile::visit (const TyTy::ADTType &type) = Backend::named_type (variant->get_ident ().path.get (), variant_record, variant->get_ident ().locus); - // set the qualifier to be a builtin - DECL_ARTIFICIAL (TYPE_FIELDS (variant_record)) = 1; - // add them to the list variant_records.push_back (named_variant_record); } @@ -358,8 +375,27 @@ TyTyResolveCompile::visit (const TyTy::ADTType &type) enum_fields.push_back (std::move (f)); } + // + location_t locus = ctx->get_mappings ().lookup_location (type.get_ref ()); + // finally make the union or the enum - type_record = Backend::union_type (enum_fields); + tree variants_union = Backend::union_type (enum_fields, false); + layout_type (variants_union); + tree named_union_record + = Backend::named_type ("payload", variants_union, locus); + + // create the overall struct + tree enumeral_type = TyTyResolveCompile::get_implicit_enumeral_node_type ( + type.get_repr_options ().repr); + Backend::typed_identifier discrim (RUST_ENUM_DISR_FIELD_NAME, + enumeral_type, locus); + Backend::typed_identifier variants_union_field ("payload", + named_union_record, + locus); + + std::vector<Backend::typed_identifier> fields + = {discrim, variants_union_field}; + type_record = Backend::struct_type (fields, false); } // Handle repr options @@ -381,6 +417,7 @@ TyTyResolveCompile::visit (const TyTy::ADTType &type) SET_TYPE_ALIGN (type_record, repr.align * 8); TYPE_USER_ALIGN (type_record) = 1; } + layout_type (type_record); std::string named_struct_str = type.get_ident ().path.get () + type.subst_as_string (); @@ -393,7 +430,7 @@ TyTyResolveCompile::visit (const TyTy::TupleType &type) { if (type.num_fields () == 0) { - translated = get_unit_type (); + translated = get_unit_type (ctx); return; } @@ -428,12 +465,24 @@ TyTyResolveCompile::visit (const TyTy::ArrayType &type) = TyTyResolveCompile::compile (ctx, type.get_element_type ()); ctx->push_const_context (); - tree capacity_expr = CompileExpr::Compile (&type.get_capacity_expr (), ctx); + + HIR::Expr &hir_capacity_expr = type.get_capacity_expr (); + TyTy::BaseType *capacity_expr_ty = nullptr; + bool ok = ctx->get_tyctx ()->lookup_type ( + hir_capacity_expr.get_mappings ().get_hirid (), &capacity_expr_ty); + rust_assert (ok); + tree capacity_expr = HIRCompileBase::compile_constant_expr ( + ctx, hir_capacity_expr.get_mappings ().get_hirid (), capacity_expr_ty, + capacity_expr_ty, Resolver::CanonicalPath::create_empty (), + hir_capacity_expr, type.get_locus (), hir_capacity_expr.get_locus ()); + ctx->pop_const_context (); tree folded_capacity_expr = fold_expr (capacity_expr); translated = Backend::array_type (element_type, folded_capacity_expr); + if (translated != error_mark_node) + translated = ctx->insert_compiled_type (translated); } void @@ -686,7 +735,7 @@ TyTyResolveCompile::visit (const TyTy::StrType &type) void TyTyResolveCompile::visit (const TyTy::NeverType &) { - translated = get_unit_type (); + translated = get_unit_type (ctx); } void @@ -703,6 +752,12 @@ TyTyResolveCompile::visit (const TyTy::DynamicObjectType &type) type.get_ident ().locus); } +void +TyTyResolveCompile::visit (const TyTy::OpaqueType &type) +{ + translated = error_mark_node; +} + tree TyTyResolveCompile::create_dyn_obj_record (const TyTy::DynamicObjectType &type) { diff --git a/gcc/rust/backend/rust-compile-type.h b/gcc/rust/backend/rust-compile-type.h index e01ca43..7ebc4a6 100644 --- a/gcc/rust/backend/rust-compile-type.h +++ b/gcc/rust/backend/rust-compile-type.h @@ -30,9 +30,7 @@ public: static tree compile (Context *ctx, const TyTy::BaseType *ty, bool trait_object_mode = false); - static tree get_implicit_enumeral_node_type (); - - static tree get_unit_type (); + static tree get_unit_type (Context *ctx); void visit (const TyTy::InferType &) override; void visit (const TyTy::ADTType &) override; @@ -58,6 +56,7 @@ public: void visit (const TyTy::ProjectionType &) override; void visit (const TyTy::DynamicObjectType &) override; void visit (const TyTy::ClosureType &) override; + void visit (const TyTy::OpaqueType &) override; public: static hashval_t type_hasher (tree type); @@ -66,6 +65,7 @@ protected: tree create_slice_type_record (const TyTy::SliceType &type); tree create_str_type_record (const TyTy::StrType &type); tree create_dyn_obj_record (const TyTy::DynamicObjectType &type); + tree get_implicit_enumeral_node_type (TyTy::BaseType *repr); private: TyTyResolveCompile (Context *ctx, bool trait_object_mode); diff --git a/gcc/rust/backend/rust-compile-var-decl.h b/gcc/rust/backend/rust-compile-var-decl.h index 6b6af77..4c46a7b 100644 --- a/gcc/rust/backend/rust-compile-var-decl.h +++ b/gcc/rust/backend/rust-compile-var-decl.h @@ -68,12 +68,12 @@ public: void visit (HIR::TuplePattern &pattern) override { - switch (pattern.get_items ()->get_item_type ()) + switch (pattern.get_items ().get_item_type ()) { case HIR::TuplePatternItems::ItemType::MULTIPLE: { rust_assert (TREE_CODE (translated_type) == RECORD_TYPE); auto &items = static_cast<HIR::TuplePatternItemsMultiple &> ( - *pattern.get_items ()); + pattern.get_items ()); size_t offs = 0; for (auto &sub : items.get_patterns ()) diff --git a/gcc/rust/backend/rust-compile.cc b/gcc/rust/backend/rust-compile.cc index 20190c3..dbd8515 100644 --- a/gcc/rust/backend/rust-compile.cc +++ b/gcc/rust/backend/rust-compile.cc @@ -241,100 +241,84 @@ HIRCompileBase::compute_address_for_trait_item ( &receiver_bounds, const TyTy::BaseType *receiver, const TyTy::BaseType *root, location_t locus) { - // There are two cases here one where its an item which has an implementation - // within a trait-impl-block. Then there is the case where there is a default - // implementation for this within the trait. - // - // The awkward part here is that this might be a generic trait and we need to - // figure out the correct monomorphized type for this so we can resolve the - // address of the function , this is stored as part of the - // type-bound-predicate - // - // Algo: - // check if there is an impl-item for this trait-item-ref first - // else assert that the trait-item-ref has an implementation - // - // FIXME this does not support super traits - TyTy::TypeBoundPredicateItem predicate_item = predicate->lookup_associated_item (ref->get_identifier ()); rust_assert (!predicate_item.is_error ()); - // this is the expected end type + // This is the expected end type TyTy::BaseType *trait_item_type = predicate_item.get_tyty_for_receiver (root); rust_assert (trait_item_type->get_kind () == TyTy::TypeKind::FNDEF); TyTy::FnType *trait_item_fntype = static_cast<TyTy::FnType *> (trait_item_type); - // find impl-block for this trait-item-ref - HIR::ImplBlock *associated_impl_block = nullptr; - const Resolver::TraitReference *predicate_trait_ref = predicate->get (); + // Loop through the list of trait references and impls that we satisfy. + // We are looking for one that has an implementation for "ref", a trait + // item. for (auto &item : receiver_bounds) { - Resolver::TraitReference *trait_ref = item.first; HIR::ImplBlock *impl_block = item.second; - if (predicate_trait_ref->is_equal (*trait_ref)) + rust_assert (impl_block != nullptr); + + // Checks for empty impl blocks, triggered by Sized trait. + if (!impl_block->has_type ()) + continue; + + // Lookup type for potentially associated impl. + HIR::Type &self_type_path = impl_block->get_type (); + + // Convert HIR::Type to TyTy::BaseType + TyTy::BaseType *self = nullptr; + bool ok = ctx->get_tyctx ()->lookup_type ( + self_type_path.get_mappings ().get_hirid (), &self); + + rust_assert (ok); + + // Look through the relevant bounds on our type, and find which one our + // impl block satisfies + TyTy::TypeBoundPredicate *self_bound = nullptr; + for (auto &bound : self->get_specified_bounds ()) { - associated_impl_block = impl_block; - break; + const Resolver::TraitReference *bound_ref = bound.get (); + const Resolver::TraitReference *specified_ref = predicate->get (); + // If this impl is for one of our types or supertypes + if (specified_ref->satisfies_bound (*bound_ref)) + { + self_bound = &bound; + break; + } } - } - // FIXME this probably should just return error_mark_node but this helps - // debug for now since we are wrongly returning early on type-resolution - // failures, until we take advantage of more error types and error_mark_node - rust_assert (associated_impl_block != nullptr); - - // lookup self for the associated impl - std::unique_ptr<HIR::Type> &self_type_path - = associated_impl_block->get_type (); - TyTy::BaseType *self = nullptr; - bool ok = ctx->get_tyctx ()->lookup_type ( - self_type_path->get_mappings ().get_hirid (), &self); - rust_assert (ok); - - // lookup the predicate item from the self - TyTy::TypeBoundPredicate *self_bound = nullptr; - for (auto &bound : self->get_specified_bounds ()) - { - const Resolver::TraitReference *bound_ref = bound.get (); - const Resolver::TraitReference *specified_ref = predicate->get (); - if (bound_ref->is_equal (*specified_ref)) + // This impl block doesn't help us + if (self_bound == nullptr) + continue; + + // Find the specific function in the impl block that matches "ref". + // This is the one we want to compute the address for. + HIR::Function *associated_function = nullptr; + for (auto &impl_item : impl_block->get_impl_items ()) { - self_bound = &bound; - break; + bool is_function = impl_item->get_impl_item_type () + == HIR::ImplItem::ImplItemType::FUNCTION; + if (!is_function) + continue; + + HIR::Function *fn = static_cast<HIR::Function *> (impl_item.get ()); + bool found_associated_item + = fn->get_function_name ().as_string ().compare ( + ref->get_identifier ()) + == 0; + if (found_associated_item) + associated_function = fn; } - } - rust_assert (self_bound != nullptr); - - // lookup the associated item from the associated impl block - TyTy::TypeBoundPredicateItem associated_self_item - = self_bound->lookup_associated_item (ref->get_identifier ()); - rust_assert (!associated_self_item.is_error ()); - // Lookup the impl-block for the associated impl_item if it exists - HIR::Function *associated_function = nullptr; - for (auto &impl_item : associated_impl_block->get_impl_items ()) - { - bool is_function = impl_item->get_impl_item_type () - == HIR::ImplItem::ImplItemType::FUNCTION; - if (!is_function) + // This impl block satisfies the bound, but doesn't contain the relevant + // function. This could happen because of supertraits. + if (associated_function == nullptr) continue; - HIR::Function *fn = static_cast<HIR::Function *> (impl_item.get ()); - bool found_associated_item - = fn->get_function_name ().as_string ().compare (ref->get_identifier ()) - == 0; - if (found_associated_item) - associated_function = fn; - } - - // we found an impl_item for this - if (associated_function != nullptr) - { // lookup the associated type for this item TyTy::BaseType *lookup = nullptr; - bool ok = ctx->get_tyctx ()->lookup_type ( + ok = ctx->get_tyctx ()->lookup_type ( associated_function->get_mappings ().get_hirid (), &lookup); rust_assert (ok); rust_assert (lookup->get_kind () == TyTy::TypeKind::FNDEF); @@ -354,7 +338,7 @@ HIRCompileBase::compute_address_for_trait_item ( } return CompileInherentImplItem::Compile (associated_function, ctx, - lookup_fntype, true, locus); + lookup_fntype, locus); } // we can only compile trait-items with a body diff --git a/gcc/rust/backend/rust-constexpr.cc b/gcc/rust/backend/rust-constexpr.cc index bfd7d95..dc2d6b1 100644 --- a/gcc/rust/backend/rust-constexpr.cc +++ b/gcc/rust/backend/rust-constexpr.cc @@ -2697,10 +2697,8 @@ eval_store_expression (const constexpr_ctx *ctx, tree t, bool lval, } if (TREE_CODE (probe) == ARRAY_REF) { - // TODO - rust_unreachable (); - // elt = eval_and_check_array_index (ctx, probe, false, - // non_constant_p, overflow_p); + elt = eval_and_check_array_index (ctx, probe, false, + non_constant_p, overflow_p); if (*non_constant_p) return t; } @@ -2929,8 +2927,13 @@ eval_store_expression (const constexpr_ctx *ctx, tree t, bool lval, } } + if (*non_constant_p) + return t; + /* Don't share a CONSTRUCTOR that might be changed later. */ init = unshare_constructor (init); + if (init == NULL_TREE) + return t; if (*valp && TREE_CODE (*valp) == CONSTRUCTOR && TREE_CODE (init) == CONSTRUCTOR) @@ -3585,9 +3588,6 @@ eval_call_expression (const constexpr_ctx *ctx, tree t, bool lval, result = *ctx->global->values.get (res); if (result == NULL_TREE && !*non_constant_p) { - if (!ctx->quiet) - error ("%<constexpr%> call flows off the end " - "of the function"); *non_constant_p = true; } } diff --git a/gcc/rust/backend/rust-mangle-legacy.cc b/gcc/rust/backend/rust-mangle-legacy.cc index 2c0ddd9..7671982 100644 --- a/gcc/rust/backend/rust-mangle-legacy.cc +++ b/gcc/rust/backend/rust-mangle-legacy.cc @@ -21,7 +21,6 @@ #include "rust-unicode.h" #include "rust-diagnostics.h" #include "rust-system.h" -#include <sstream> namespace Rust { namespace Compile { diff --git a/gcc/rust/backend/rust-mangle-v0.cc b/gcc/rust/backend/rust-mangle-v0.cc index d604dcf..d0df4ab 100644 --- a/gcc/rust/backend/rust-mangle-v0.cc +++ b/gcc/rust/backend/rust-mangle-v0.cc @@ -25,7 +25,6 @@ #include "rust-unicode.h" #include "rust-punycode.h" #include "rust-compile-type.h" -#include <sstream> namespace Rust { namespace Compile { @@ -328,7 +327,7 @@ v0_inherent_or_trait_impl_path (Rust::Compile::Context *ctx, // lookup impl type TyTy::BaseType *impl_ty = nullptr; ok = ctx->get_tyctx ()->lookup_type ( - impl_block->get_type ()->get_mappings ().get_hirid (), &impl_ty); + impl_block->get_type ().get_mappings ().get_hirid (), &impl_ty); rust_assert (ok); // FIXME: dummy value for now @@ -342,7 +341,7 @@ v0_inherent_or_trait_impl_path (Rust::Compile::Context *ctx, TyTy::BaseType *trait_ty = nullptr; ok = ctx->get_tyctx ()->lookup_type ( - impl_block->get_trait_ref ()->get_mappings ().get_hirid (), &trait_ty); + impl_block->get_trait_ref ().get_mappings ().get_hirid (), &trait_ty); rust_assert (ok); v0path.trait_type = v0_type_prefix (ctx, trait_ty); diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/Cargo.lock b/gcc/rust/checks/errors/borrowck/ffi-polonius/Cargo.lock new file mode 100644 index 0000000..1b223b6 --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/Cargo.lock @@ -0,0 +1,29 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "datafrog" +version = "2.0.1" + +[[package]] +name = "ffi-polonius" +version = "0.1.0" +dependencies = [ + "polonius-engine", +] + +[[package]] +name = "log" +version = "0.4.22" + +[[package]] +name = "polonius-engine" +version = "0.13.0" +dependencies = [ + "datafrog", + "log", + "rustc-hash", +] + +[[package]] +name = "rustc-hash" +version = "1.1.0" diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/Cargo.toml b/gcc/rust/checks/errors/borrowck/ffi-polonius/Cargo.toml index 71315c3..3bc8e3f 100644 --- a/gcc/rust/checks/errors/borrowck/ffi-polonius/Cargo.toml +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/Cargo.toml @@ -1,11 +1,17 @@ [package] name = "ffi-polonius" version = "0.1.0" -edition = "2021" +edition = "2018" license = "GPL-3" [lib] crate-type = ["staticlib"] [dependencies] -polonius-engine = "0.13.0"
\ No newline at end of file +polonius-engine = "0.13.0" + +[patch.crates-io] +log = { path = "vendor/log" } +datafrog = { path = "vendor/datafrog" } +polonius-engine = { path = "vendor/polonius-engine" } +rustc-hash = { path = "vendor/rustc-hash" } diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/src/gccrs_ffi.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/src/gccrs_ffi.rs index 0cb8507..7377e3a 100644 --- a/gcc/rust/checks/errors/borrowck/ffi-polonius/src/gccrs_ffi.rs +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/src/gccrs_ffi.rs @@ -30,11 +30,16 @@ // ``` include!("gccrs_ffi_generated.rs"); +use std::marker::{PhantomData, PhantomPinned}; + use crate::GccrsAtom; -// Using opqaue types -extern "C" { - pub type FFIVector; +// We define an opaque C type per the nomicon's recommendation: +// https://doc.rust-lang.org/nomicon/ffi.html#representing-opaque-structs +#[repr(C)] +pub struct FFIVector { + _empty: [u8; 0], + marker: PhantomData<(*mut u8, PhantomPinned)>, } impl<T1, T2> Into<(GccrsAtom, GccrsAtom)> for Pair<T1, T2> diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/src/lib.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/src/lib.rs index 782a63f..b21dee3 100644 --- a/gcc/rust/checks/errors/borrowck/ffi-polonius/src/lib.rs +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/src/lib.rs @@ -16,8 +16,6 @@ // along with GCC; see the file COPYING3. If not see // <http://www.gnu.org/licenses/>. -#![feature(extern_types)] - mod gccrs_ffi; use gccrs_ffi::FFIVector; @@ -107,9 +105,24 @@ impl From<gccrs_ffi::FactsView> for AllFacts<GccrsFacts> { fn print_point(point: GccrsAtom) { let val: usize = point.into(); + // Point is a 32 bit unsigned integer + // 16 15 1 + // xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxx x + // ^~~~~~~~~~~~~~~~ ^~~~~~~~~~~~~~~ ^ + // | | | + // basic_block | start/mid + // statement + // the left most 16 bits store the basic block number + // the right most bit, represents the start/mid status + // the remaining 15 bits between these two represent the statement let mid = val % 2 == 1; let bb = val >> 16; - let stmt = (val >> 1) & ((1 << 15) - 1); + // firstly we can get rid of right most bit by performing left shift once + let hide_left_most_bit = val >> 1; + // now we only need the 15 bits on the right + // we can mask the remaining bits by performing bitwise AND with fifteen + // 1's which in hexadecimal is 0x7FFF + let stmt = hide_left_most_bit & 0x7FFF; eprint!("{}(bb{}[{}])", if mid { "Mid" } else { "Start" }, bb, stmt); } diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/.cargo-checksum.json b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/.cargo-checksum.json new file mode 100644 index 0000000..80aa32c --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CODE_OF_CONDUCT.md":"edca092fde496419a9f1ba640048aa0270b62dfea576cd3175f0b53e3c230470","Cargo.toml":"c3a8ecf831d7985fafcb8e523fd2d1bf875297e1a11b750a28222793a42e0d4c","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"60c181bf865b494df30968378509453719163f57a84f31a244fe69e62c342c5b","RELEASES.md":"a49128d725075bb614da3d53ea2aa2ab080bcb83ce46fc57655f6f6ecc9e2b74","examples/borrow_check.rs":"256857ed6609be8d1f3c8cf041ff8a1c0a884e8540f3156d2f3a2a2a9f73a05d","examples/graspan1.rs":"7d93ba71ff08a3667fea696d0a94e2c91e7514c304f2be8b088465cee17537fe","src/join.rs":"04eb29a02a1fd3ecf27d35a9eaabeec686bbfabdeafe13ad9ac98a622acb0f19","src/lib.rs":"7c95a63c237f48f986abd63ddfa4ed296bb5d280d245295d025fdf2f9744c2f3","src/map.rs":"93f1c7273fb67beb62a4b02201a6502bcaabf1e079aa7201a88d8e0aea6123e9","src/test.rs":"1eee5db2817a781cf8bf16744338b896252e400c150ae23ad87ce8c623acee69","src/treefrog.rs":"fe84a2bd2e36f1a48cb6b7e77a74addf218cfc881e9f6d4e7ceff4d8d97aa380"},"package":"a0afaad2b26fa326569eb264b1363e8ae3357618c43982b3f285f0774ce76b69"}
\ No newline at end of file diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/CODE_OF_CONDUCT.md b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..d70b2b5 --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/CODE_OF_CONDUCT.md @@ -0,0 +1,40 @@ +# The Rust Code of Conduct + +A version of this document [can be found online](https://www.rust-lang.org/conduct.html). + +## Conduct + +**Contact**: [rust-mods@rust-lang.org](mailto:rust-mods@rust-lang.org) + +* We are committed to providing a friendly, safe and welcoming environment for all, regardless of level of experience, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, nationality, or other similar characteristic. +* On IRC, please avoid using overtly sexual nicknames or other nicknames that might detract from a friendly, safe and welcoming environment for all. +* Please be kind and courteous. There's no need to be mean or rude. +* Respect that people have differences of opinion and that every design or implementation choice carries a trade-off and numerous costs. There is seldom a right answer. +* Please keep unstructured critique to a minimum. If you have solid ideas you want to experiment with, make a fork and see how it works. +* We will exclude you from interaction if you insult, demean or harass anyone. That is not welcome behavior. We interpret the term "harassment" as including the definition in the <a href="http://citizencodeofconduct.org/">Citizen Code of Conduct</a>; if you have any lack of clarity about what might be included in that concept, please read their definition. In particular, we don't tolerate behavior that excludes people in socially marginalized groups. +* Private harassment is also unacceptable. No matter who you are, if you feel you have been or are being harassed or made uncomfortable by a community member, please contact one of the channel ops or any of the [Rust moderation team][mod_team] immediately. Whether you're a regular contributor or a newcomer, we care about making this community a safe place for you and we've got your back. +* Likewise any spamming, trolling, flaming, baiting or other attention-stealing behavior is not welcome. + +## Moderation + + +These are the policies for upholding our community's standards of conduct. If you feel that a thread needs moderation, please contact the [Rust moderation team][mod_team]. + +1. Remarks that violate the Rust standards of conduct, including hateful, hurtful, oppressive, or exclusionary remarks, are not allowed. (Cursing is allowed, but never targeting another user, and never in a hateful manner.) +2. Remarks that moderators find inappropriate, whether listed in the code of conduct or not, are also not allowed. +3. Moderators will first respond to such remarks with a warning. +4. If the warning is unheeded, the user will be "kicked," i.e., kicked out of the communication channel to cool off. +5. If the user comes back and continues to make trouble, they will be banned, i.e., indefinitely excluded. +6. Moderators may choose at their discretion to un-ban the user if it was a first offense and they offer the offended party a genuine apology. +7. If a moderator bans someone and you think it was unjustified, please take it up with that moderator, or with a different moderator, **in private**. Complaints about bans in-channel are not allowed. +8. Moderators are held to a higher standard than other community members. If a moderator creates an inappropriate situation, they should expect less leeway than others. + +In the Rust community we strive to go the extra step to look out for each other. Don't just aim to be technically unimpeachable, try to be your best self. In particular, avoid flirting with offensive or sensitive issues, particularly if they're off-topic; this all too often leads to unnecessary fights, hurt feelings, and damaged trust; worse, it can drive people away from the community entirely. + +And if someone takes issue with something you said or did, resist the urge to be defensive. Just stop doing what it was they complained about and apologize. Even if you feel you were misinterpreted or unfairly accused, chances are good there was something you could've communicated better — remember that it's your responsibility to make your fellow Rustaceans comfortable. Everyone wants to get along and we are all here first and foremost because we want to talk about cool technology. You will find that people will be eager to assume good intent and forgive as long as you earn their trust. + +The enforcement policies listed above apply to all official Rust venues; including official IRC channels (#rust, #rust-internals, #rust-tools, #rust-libs, #rustc, #rust-beginners, #rust-docs, #rust-community, #rust-lang, and #cargo); GitHub repositories under rust-lang, rust-lang-nursery, and rust-lang-deprecated; and all forums under rust-lang.org (users.rust-lang.org, internals.rust-lang.org). For other projects adopting the Rust Code of Conduct, please contact the maintainers of those projects for enforcement. If you wish to use this code of conduct for your own project, consider explicitly mentioning your moderation policy or making a copy with your own moderation policy so as to avoid confusion. + +*Adapted from the [Node.js Policy on Trolling](http://blog.izs.me/post/30036893703/policy-on-trolling) as well as the [Contributor Covenant v1.3.0](https://www.contributor-covenant.org/version/1/3/0/).* + +[mod_team]: https://www.rust-lang.org/team.html#Moderation-team diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/Cargo.toml b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/Cargo.toml new file mode 100644 index 0000000..71bccdd --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/Cargo.toml @@ -0,0 +1,29 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "datafrog" +version = "2.0.1" +authors = ["Frank McSherry <fmcsherry@me.com>", "The Rust Project Developers", "Datafrog Developers"] +description = "Lightweight Datalog engine intended to be embedded in other Rust programs" +readme = "README.md" +keywords = ["datalog", "analysis"] +license = "Apache-2.0/MIT" +repository = "https://github.com/rust-lang-nursery/datafrog" +[dev-dependencies.proptest] +version = "0.8.7" +[badges.is-it-maintained-issue-resolution] +repository = "https://github.com/rust-lang-nursery/datafrog" + +[badges.is-it-maintained-open-issues] +repository = "https://github.com/rust-lang-nursery/datafrog" diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/LICENSE-APACHE b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/LICENSE-APACHE new file mode 100644 index 0000000..16fe87b --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/LICENSE-MIT b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/LICENSE-MIT new file mode 100644 index 0000000..31aa793 --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/LICENSE-MIT @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/README.md b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/README.md new file mode 100644 index 0000000..9483584 --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/README.md @@ -0,0 +1,44 @@ +# datafrog + +Datafrog is a lightweight Datalog engine intended to be embedded in other Rust programs. + +Datafrog has no runtime, and relies on you to build and repeatedly apply the update rules. +It tries to help you do this correctly. As an example, here is how you might write a reachability +query using Datafrog (minus the part where we populate the `nodes` and `edges` initial relations). + +```rust +extern crate datafrog; +use datafrog::Iteration; + +fn main() { + + // Create a new iteration context, ... + let mut iteration = Iteration::new(); + + // .. some variables, .. + let nodes_var = iteration.variable::<(u32,u32)>("nodes"); + let edges_var = iteration.variable::<(u32,u32)>("edges"); + + // .. load them with some initial values, .. + nodes_var.insert(nodes.into()); + edges_var.insert(edges.into()); + + // .. and then start iterating rules! + while iteration.changed() { + // nodes(a,c) <- nodes(a,b), edges(b,c) + nodes_var.from_join(&nodes_var, &edges_var, |_b, &a, &c| (c,a)); + } + + // extract the final results. + let reachable: Vec<(u32,u32)> = variable.complete(); +} +``` + +If you'd like to read more about how it works, check out [this blog post](https://github.com/frankmcsherry/blog/blob/master/posts/2018-05-19.md). + +## Authorship + +Datafrog was initially developed by [Frank McSherry][fmc] and was +later transferred to the rust-lang-nursery organization. Thanks Frank! + +[fmc]: https://github.com/frankmcsherry diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/RELEASES.md b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/RELEASES.md new file mode 100644 index 0000000..7d666f6 --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/RELEASES.md @@ -0,0 +1,26 @@ +# 2.0.1 + +- Work around a rustdoc ICE (#24) + +# 2.0.0 + +- Breaking changes: + - leapjoin now takes a tuple of leapers, and not a `&mut` slice: + - `from_leapjoin(&input, &mut [&mut foo.extend_with(...), ..], ..)` becomes + `from_leapjoin(&input, (foo.extend_with(...), ..), ..)` + - if there is only one leaper, no tuple is needed + - `Relation::from` now requires a vector, not an iterator; use + `Relation::from_iter` instead +- Changed the API to permit using `Relation` and `Variable` more interchangeably, + and added a number of operations to construct relations directly, like `Relation::from_join` +- Extended leapfrog triejoin with new operations (`PrefixFilter` and `ValueFilter`) + +# 1.0.0 + +- Added leapfrog triejoin (#11). +- Have badges and repo links now! +- Minor performance improvements (#13). + +# 0.1.0 + +- Initial release. diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/examples/borrow_check.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/examples/borrow_check.rs new file mode 100644 index 0000000..8f2197a --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/examples/borrow_check.rs @@ -0,0 +1,115 @@ +extern crate datafrog; +use datafrog::Iteration; + +type Region = u32; +type Borrow = u32; +type Point = u32; + +fn main() { + let subset = { + // Create a new iteration context, ... + let mut iteration1 = Iteration::new(); + + // .. some variables, .. + let subset = iteration1.variable::<(Region, Region, Point)>("subset"); + + // different indices for `subset`. + let subset_r1p = iteration1.variable::<((Region, Point), Region)>("subset_r1p"); + let subset_r2p = iteration1.variable::<((Region, Point), Region)>("subset_r2p"); + let subset_p = iteration1.variable::<(Point, (Region, Region))>("subset_p"); + + // temporaries as we perform a multi-way join. + let subset_1 = iteration1.variable::<((Region, Point), Region)>("subset_1"); + let subset_2 = iteration1.variable::<((Region, Point), Region)>("subset_2"); + + let region_live_at = iteration1.variable::<((Region, Point), ())>("region_live_at"); + let cfg_edge_p = iteration1.variable::<(Point, Point)>("cfg_edge_p"); + + // load initial facts. + subset.insert(Vec::new().into()); + region_live_at.insert(Vec::new().into()); + cfg_edge_p.insert(Vec::new().into()); + + // .. and then start iterating rules! + while iteration1.changed() { + // remap fields to re-index by keys. + subset_r1p.from_map(&subset, |&(r1, r2, p)| ((r1, p), r2)); + subset_r2p.from_map(&subset, |&(r1, r2, p)| ((r2, p), r1)); + subset_p.from_map(&subset, |&(r1, r2, p)| (p, (r1, r2))); + + // R0: subset(R1, R2, P) :- outlives(R1, R2, P). + // Already loaded; outlives is static. + + // R1: subset(R1, R3, P) :- + // subset(R1, R2, P), + // subset(R2, R3, P). + subset.from_join(&subset_r2p, &subset_r1p, |&(_r2, p), &r1, &r3| (r1, r3, p)); + + // R2: subset(R1, R2, Q) :- + // subset(R1, R2, P), + // cfg_edge(P, Q), + // region_live_at(R1, Q), + // region_live_at(R2, Q). + + subset_1.from_join(&subset_p, &cfg_edge_p, |&_p, &(r1, r2), &q| ((r1, q), r2)); + subset_2.from_join(&subset_1, ®ion_live_at, |&(r1, q), &r2, &()| { + ((r2, q), r1) + }); + subset.from_join(&subset_2, ®ion_live_at, |&(r2, q), &r1, &()| (r1, r2, q)); + } + + subset_r1p.complete() + }; + + let _requires = { + // Create a new iteration context, ... + let mut iteration2 = Iteration::new(); + + // .. some variables, .. + let requires = iteration2.variable::<(Region, Borrow, Point)>("requires"); + requires.insert(Vec::new().into()); + + let requires_rp = iteration2.variable::<((Region, Point), Borrow)>("requires_rp"); + let requires_bp = iteration2.variable::<((Borrow, Point), Region)>("requires_bp"); + + let requires_1 = iteration2.variable::<(Point, (Borrow, Region))>("requires_1"); + let requires_2 = iteration2.variable::<((Region, Point), Borrow)>("requires_2"); + + let subset_r1p = iteration2.variable::<((Region, Point), Region)>("subset_r1p"); + subset_r1p.insert(subset); + + let killed = Vec::new().into(); + let region_live_at = iteration2.variable::<((Region, Point), ())>("region_live_at"); + let cfg_edge_p = iteration2.variable::<(Point, Point)>("cfg_edge_p"); + + // .. and then start iterating rules! + while iteration2.changed() { + requires_rp.from_map(&requires, |&(r, b, p)| ((r, p), b)); + requires_bp.from_map(&requires, |&(r, b, p)| ((b, p), r)); + + // requires(R, B, P) :- borrow_region(R, B, P). + // Already loaded; borrow_region is static. + + // requires(R2, B, P) :- + // requires(R1, B, P), + // subset(R1, R2, P). + requires.from_join(&requires_rp, &subset_r1p, |&(_r1, p), &b, &r2| (r2, b, p)); + + // requires(R, B, Q) :- + // requires(R, B, P), + // !killed(B, P), + // cfg_edge(P, Q), + // (region_live_at(R, Q); universal_region(R)). + + requires_1.from_antijoin(&requires_bp, &killed, |&(b, p), &r| (p, (b, r))); + requires_2.from_join(&requires_1, &cfg_edge_p, |&_p, &(b, r), &q| ((r, q), b)); + requires.from_join(&requires_2, ®ion_live_at, |&(r, q), &b, &()| (r, b, q)); + } + + requires.complete() + }; + + // borrow_live_at(B, P) :- requires(R, B, P), region_live_at(R, P) + + // borrow_live_at(B, P) :- requires(R, B, P), universal_region(R). +} diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/examples/graspan1.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/examples/graspan1.rs new file mode 100644 index 0000000..31225b1 --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/examples/graspan1.rs @@ -0,0 +1,62 @@ +extern crate datafrog; +use datafrog::Iteration; + +fn main() { + let timer = ::std::time::Instant::now(); + + // Make space for input data. + let mut nodes = Vec::new(); + let mut edges = Vec::new(); + + // Read input data from a handy file. + use std::fs::File; + use std::io::{BufRead, BufReader}; + + let filename = std::env::args().nth(1).unwrap(); + let file = BufReader::new(File::open(filename).unwrap()); + for readline in file.lines() { + let line = readline.expect("read error"); + if !line.is_empty() && !line.starts_with('#') { + let mut elts = line[..].split_whitespace(); + let src: u32 = elts.next().unwrap().parse().expect("malformed src"); + let dst: u32 = elts.next().unwrap().parse().expect("malformed dst"); + let typ: &str = elts.next().unwrap(); + match typ { + "n" => { + nodes.push((dst, src)); + } + "e" => { + edges.push((src, dst)); + } + unk => panic!("unknown type: {}", unk), + } + } + } + + println!("{:?}\tData loaded", timer.elapsed()); + + // Create a new iteration context, ... + let mut iteration = Iteration::new(); + + // .. some variables, .. + let variable1 = iteration.variable::<(u32, u32)>("nodes"); + let variable2 = iteration.variable::<(u32, u32)>("edges"); + + // .. load them with some initial values, .. + variable1.insert(nodes.into()); + variable2.insert(edges.into()); + + // .. and then start iterating rules! + while iteration.changed() { + // N(a,c) <- N(a,b), E(b,c) + variable1.from_join(&variable1, &variable2, |_b, &a, &c| (c, a)); + } + + let reachable = variable1.complete(); + + println!( + "{:?}\tComputation complete (nodes_final: {})", + timer.elapsed(), + reachable.len() + ); +} diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/src/join.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/src/join.rs new file mode 100644 index 0000000..94270af --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/src/join.rs @@ -0,0 +1,180 @@ +//! Join functionality. + +use super::{Relation, Variable}; +use std::cell::Ref; +use std::ops::Deref; + +/// Implements `join`. Note that `input1` must be a variable, but +/// `input2` can be either a variable or a relation. This is necessary +/// because relations have no "recent" tuples, so the fn would be a +/// guaranteed no-op if both arguments were relations. See also +/// `join_into_relation`. +pub(crate) fn join_into<'me, Key: Ord, Val1: Ord, Val2: Ord, Result: Ord>( + input1: &Variable<(Key, Val1)>, + input2: impl JoinInput<'me, (Key, Val2)>, + output: &Variable<Result>, + mut logic: impl FnMut(&Key, &Val1, &Val2) -> Result, +) { + let mut results = Vec::new(); + + let recent1 = input1.recent(); + let recent2 = input2.recent(); + + { + // scoped to let `closure` drop borrow of `results`. + + let mut closure = |k: &Key, v1: &Val1, v2: &Val2| results.push(logic(k, v1, v2)); + + for batch2 in input2.stable().iter() { + join_helper(&recent1, &batch2, &mut closure); + } + + for batch1 in input1.stable().iter() { + join_helper(&batch1, &recent2, &mut closure); + } + + join_helper(&recent1, &recent2, &mut closure); + } + + output.insert(Relation::from_vec(results)); +} + +/// Join, but for two relations. +pub(crate) fn join_into_relation<'me, Key: Ord, Val1: Ord, Val2: Ord, Result: Ord>( + input1: &Relation<(Key, Val1)>, + input2: &Relation<(Key, Val2)>, + mut logic: impl FnMut(&Key, &Val1, &Val2) -> Result, +) -> Relation<Result> { + let mut results = Vec::new(); + + join_helper(&input1.elements, &input2.elements, |k, v1, v2| { + results.push(logic(k, v1, v2)); + }); + + Relation::from_vec(results) +} + +/// Moves all recent tuples from `input1` that are not present in `input2` into `output`. +pub(crate) fn antijoin<'me, Key: Ord, Val: Ord, Result: Ord>( + input1: impl JoinInput<'me, (Key, Val)>, + input2: &Relation<Key>, + mut logic: impl FnMut(&Key, &Val) -> Result, +) -> Relation<Result> { + let mut tuples2 = &input2[..]; + + let results = input1 + .recent() + .iter() + .filter(|(ref key, _)| { + tuples2 = gallop(tuples2, |k| k < key); + tuples2.first() != Some(key) + }) + .map(|(ref key, ref val)| logic(key, val)) + .collect::<Vec<_>>(); + + Relation::from_vec(results) +} + +fn join_helper<K: Ord, V1, V2>( + mut slice1: &[(K, V1)], + mut slice2: &[(K, V2)], + mut result: impl FnMut(&K, &V1, &V2), +) { + while !slice1.is_empty() && !slice2.is_empty() { + use std::cmp::Ordering; + + // If the keys match produce tuples, else advance the smaller key until they might. + match slice1[0].0.cmp(&slice2[0].0) { + Ordering::Less => { + slice1 = gallop(slice1, |x| x.0 < slice2[0].0); + } + Ordering::Equal => { + // Determine the number of matching keys in each slice. + let count1 = slice1.iter().take_while(|x| x.0 == slice1[0].0).count(); + let count2 = slice2.iter().take_while(|x| x.0 == slice2[0].0).count(); + + // Produce results from the cross-product of matches. + for index1 in 0..count1 { + for s2 in slice2[..count2].iter() { + result(&slice1[0].0, &slice1[index1].1, &s2.1); + } + } + + // Advance slices past this key. + slice1 = &slice1[count1..]; + slice2 = &slice2[count2..]; + } + Ordering::Greater => { + slice2 = gallop(slice2, |x| x.0 < slice1[0].0); + } + } + } +} + +pub(crate) fn gallop<T>(mut slice: &[T], mut cmp: impl FnMut(&T) -> bool) -> &[T] { + // if empty slice, or already >= element, return + if !slice.is_empty() && cmp(&slice[0]) { + let mut step = 1; + while step < slice.len() && cmp(&slice[step]) { + slice = &slice[step..]; + step <<= 1; + } + + step >>= 1; + while step > 0 { + if step < slice.len() && cmp(&slice[step]) { + slice = &slice[step..]; + } + step >>= 1; + } + + slice = &slice[1..]; // advance one, as we always stayed < value + } + + slice +} + +/// An input that can be used with `from_join`; either a `Variable` or a `Relation`. +pub trait JoinInput<'me, Tuple: Ord>: Copy { + /// If we are on iteration N of the loop, these are the tuples + /// added on iteration N-1. (For a `Relation`, this is always an + /// empty slice.) + type RecentTuples: Deref<Target = [Tuple]>; + + /// If we are on iteration N of the loop, these are the tuples + /// added on iteration N - 2 or before. (For a `Relation`, this is + /// just `self`.) + type StableTuples: Deref<Target = [Relation<Tuple>]>; + + /// Get the set of recent tuples. + fn recent(self) -> Self::RecentTuples; + + /// Get the set of stable tuples. + fn stable(self) -> Self::StableTuples; +} + +impl<'me, Tuple: Ord> JoinInput<'me, Tuple> for &'me Variable<Tuple> { + type RecentTuples = Ref<'me, [Tuple]>; + type StableTuples = Ref<'me, [Relation<Tuple>]>; + + fn recent(self) -> Self::RecentTuples { + Ref::map(self.recent.borrow(), |r| &r.elements[..]) + } + + fn stable(self) -> Self::StableTuples { + Ref::map(self.stable.borrow(), |v| &v[..]) + } +} + +impl<'me, Tuple: Ord> JoinInput<'me, Tuple> for &'me Relation<Tuple> { + type RecentTuples = &'me [Tuple]; + type StableTuples = &'me [Relation<Tuple>]; + + fn recent(self) -> Self::RecentTuples { + &[] + } + + fn stable(self) -> Self::StableTuples { + std::slice::from_ref(self) + } +} diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/src/lib.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/src/lib.rs new file mode 100644 index 0000000..d2f9323 --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/src/lib.rs @@ -0,0 +1,567 @@ +//! A lightweight Datalog engine in Rust +//! +//! The intended design is that one has static `Relation` types that are sets +//! of tuples, and `Variable` types that represent monotonically increasing +//! sets of tuples. +//! +//! The types are mostly wrappers around `Vec<Tuple>` indicating sorted-ness, +//! and the intent is that this code can be dropped in the middle of an otherwise +//! normal Rust program, run to completion, and then the results extracted as +//! vectors again. + +#![forbid(missing_docs)] + +use std::cell::RefCell; +use std::cmp::Ordering; +use std::iter::FromIterator; +use std::rc::Rc; + +mod join; +mod map; +mod test; +mod treefrog; +pub use crate::join::JoinInput; +pub use crate::treefrog::{ + extend_anti::ExtendAnti, + extend_with::ExtendWith, + filter_anti::FilterAnti, + filter_with::FilterWith, + filters::{PrefixFilter, ValueFilter}, + Leaper, Leapers, RelationLeaper, +}; + +/// A static, ordered list of key-value pairs. +/// +/// A relation represents a fixed set of key-value pairs. In many places in a +/// Datalog computation we want to be sure that certain relations are not able +/// to vary (for example, in antijoins). +#[derive(Clone)] +pub struct Relation<Tuple: Ord> { + /// Sorted list of distinct tuples. + pub elements: Vec<Tuple>, +} + +impl<Tuple: Ord> Relation<Tuple> { + /// Merges two relations into their union. + pub fn merge(self, other: Self) -> Self { + let Relation { + elements: mut elements1, + } = self; + let Relation { + elements: mut elements2, + } = other; + + // If one of the element lists is zero-length, we don't need to do any work + if elements1.is_empty() { + return Relation { + elements: elements2, + }; + } + + if elements2.is_empty() { + return Relation { + elements: elements1, + }; + } + + // Make sure that elements1 starts with the lower element + // Will not panic since both collections must have at least 1 element at this point + if elements1[0] > elements2[0] { + std::mem::swap(&mut elements1, &mut elements2); + } + + // Fast path for when all the new elements are after the exiting ones + if elements1[elements1.len() - 1] < elements2[0] { + elements1.extend(elements2.into_iter()); + // println!("fast path"); + return Relation { + elements: elements1, + }; + } + + let mut elements = Vec::with_capacity(elements1.len() + elements2.len()); + let mut elements1 = elements1.drain(..); + let mut elements2 = elements2.drain(..).peekable(); + + elements.push(elements1.next().unwrap()); + if elements.first() == elements2.peek() { + elements2.next(); + } + + for elem in elements1 { + while elements2.peek().map(|x| x.cmp(&elem)) == Some(Ordering::Less) { + elements.push(elements2.next().unwrap()); + } + if elements2.peek().map(|x| x.cmp(&elem)) == Some(Ordering::Equal) { + elements2.next(); + } + elements.push(elem); + } + + // Finish draining second list + elements.extend(elements2); + + Relation { elements } + } + + /// Creates a `Relation` from the elements of the `iterator`. + /// + /// Same as the `from_iter` method from `std::iter::FromIterator` trait. + pub fn from_iter<I>(iterator: I) -> Self + where + I: IntoIterator<Item = Tuple>, + { + iterator.into_iter().collect() + } + + /// Creates a `Relation` using the `leapjoin` logic; + /// see [`Variable::from_leapjoin`] + pub fn from_leapjoin<'leap, SourceTuple: Ord, Val: Ord + 'leap>( + source: &Relation<SourceTuple>, + leapers: impl Leapers<'leap, SourceTuple, Val>, + logic: impl FnMut(&SourceTuple, &Val) -> Tuple, + ) -> Self { + treefrog::leapjoin(&source.elements, leapers, logic) + } + + /// Creates a `Relation` by joining the values from `input1` and + /// `input2` and then applying `logic`. Like + /// [`Variable::from_join`] except for use where the inputs are + /// not varying across iterations. + pub fn from_join<Key: Ord, Val1: Ord, Val2: Ord>( + input1: &Relation<(Key, Val1)>, + input2: &Relation<(Key, Val2)>, + logic: impl FnMut(&Key, &Val1, &Val2) -> Tuple, + ) -> Self { + join::join_into_relation(input1, input2, logic) + } + + /// Creates a `Relation` by removing all values from `input1` that + /// share a key with `input2`, and then transforming the resulting + /// tuples with the `logic` closure. Like + /// [`Variable::from_antijoin`] except for use where the inputs + /// are not varying across iterations. + pub fn from_antijoin<Key: Ord, Val1: Ord>( + input1: &Relation<(Key, Val1)>, + input2: &Relation<Key>, + logic: impl FnMut(&Key, &Val1) -> Tuple, + ) -> Self { + join::antijoin(input1, input2, logic) + } + + /// Construct a new relation by mapping another one. Equivalent to + /// creating an iterator but perhaps more convenient. Analogous to + /// `Variable::from_map`. + pub fn from_map<T2: Ord>(input: &Relation<T2>, logic: impl FnMut(&T2) -> Tuple) -> Self { + input.iter().map(logic).collect() + } + + /// Creates a `Relation` from a vector of tuples. + pub fn from_vec(mut elements: Vec<Tuple>) -> Self { + elements.sort(); + elements.dedup(); + Relation { elements } + } +} + +impl<Tuple: Ord> From<Vec<Tuple>> for Relation<Tuple> { + fn from(iterator: Vec<Tuple>) -> Self { + Self::from_vec(iterator) + } +} + +impl<Tuple: Ord> FromIterator<Tuple> for Relation<Tuple> { + fn from_iter<I>(iterator: I) -> Self + where + I: IntoIterator<Item = Tuple>, + { + Relation::from_vec(iterator.into_iter().collect()) + } +} + +impl<'tuple, Tuple: 'tuple + Copy + Ord> FromIterator<&'tuple Tuple> for Relation<Tuple> { + fn from_iter<I>(iterator: I) -> Self + where + I: IntoIterator<Item = &'tuple Tuple>, + { + Relation::from_vec(iterator.into_iter().cloned().collect()) + } +} + +impl<Tuple: Ord> std::ops::Deref for Relation<Tuple> { + type Target = [Tuple]; + fn deref(&self) -> &Self::Target { + &self.elements[..] + } +} + +/// An iterative context for recursive evaluation. +/// +/// An `Iteration` tracks monotonic variables, and monitors their progress. +/// It can inform the user if they have ceased changing, at which point the +/// computation should be done. +pub struct Iteration { + variables: Vec<Box<dyn VariableTrait>>, +} + +impl Iteration { + /// Create a new iterative context. + pub fn new() -> Self { + Iteration { + variables: Vec::new(), + } + } + /// Reports whether any of the monitored variables have changed since + /// the most recent call. + pub fn changed(&mut self) -> bool { + let mut result = false; + for variable in self.variables.iter_mut() { + if variable.changed() { + result = true; + } + } + result + } + /// Creates a new named variable associated with the iterative context. + pub fn variable<Tuple: Ord + 'static>(&mut self, name: &str) -> Variable<Tuple> { + let variable = Variable::new(name); + self.variables.push(Box::new(variable.clone())); + variable + } + /// Creates a new named variable associated with the iterative context. + /// + /// This variable will not be maintained distinctly, and may advertise tuples as + /// recent multiple times (perhaps unboundedly many times). + pub fn variable_indistinct<Tuple: Ord + 'static>(&mut self, name: &str) -> Variable<Tuple> { + let mut variable = Variable::new(name); + variable.distinct = false; + self.variables.push(Box::new(variable.clone())); + variable + } +} + +/// A type that can report on whether it has changed. +trait VariableTrait { + /// Reports whether the variable has changed since it was last asked. + fn changed(&mut self) -> bool; +} + +/// An monotonically increasing set of `Tuple`s. +/// +/// There are three stages in the lifecycle of a tuple: +/// +/// 1. A tuple is added to `self.to_add`, but is not yet visible externally. +/// 2. Newly added tuples are then promoted to `self.recent` for one iteration. +/// 3. After one iteration, recent tuples are moved to `self.tuples` for posterity. +/// +/// Each time `self.changed()` is called, the `recent` relation is folded into `tuples`, +/// and the `to_add` relations are merged, potentially deduplicated against `tuples`, and +/// then made `recent`. This way, across calls to `changed()` all added tuples are in +/// `recent` at least once and eventually all are in `tuples`. +/// +/// A `Variable` may optionally be instructed not to de-duplicate its tuples, for reasons +/// of performance. Such a variable cannot be relied on to terminate iterative computation, +/// and it is important that any cycle of derivations have at least one de-duplicating +/// variable on it. +pub struct Variable<Tuple: Ord> { + /// Should the variable be maintained distinctly. + distinct: bool, + /// A useful name for the variable. + name: String, + /// A list of relations whose union are the accepted tuples. + pub stable: Rc<RefCell<Vec<Relation<Tuple>>>>, + /// A list of recent tuples, still to be processed. + pub recent: Rc<RefCell<Relation<Tuple>>>, + /// A list of future tuples, to be introduced. + to_add: Rc<RefCell<Vec<Relation<Tuple>>>>, +} + +// Operator implementations. +impl<Tuple: Ord> Variable<Tuple> { + /// Adds tuples that result from joining `input1` and `input2` -- + /// each of the inputs must be a set of (Key, Value) tuples. Both + /// `input1` and `input2` must have the same type of key (`K`) but + /// they can have distinct value types (`V1` and `V2` + /// respectively). The `logic` closure will be invoked for each + /// key that appears in both inputs; it is also given the two + /// values, and from those it should construct the resulting + /// value. + /// + /// Note that `input1` must be a variable, but `input2` can be a + /// relation or a variable. Therefore, you cannot join two + /// relations with this method. This is not because the result + /// would be wrong, but because it would be inefficient: the + /// result from such a join cannot vary across iterations (as + /// relations are fixed), so you should prefer to invoke `insert` + /// on a relation created by `Relation::from_join` instead. + /// + /// # Examples + /// + /// This example starts a collection with the pairs (x, x+1) and (x+1, x) for x in 0 .. 10. + /// It then adds pairs (y, z) for which (x, y) and (x, z) are present. Because the initial + /// pairs are symmetric, this should result in all pairs (x, y) for x and y in 0 .. 11. + /// + /// ``` + /// use datafrog::{Iteration, Relation}; + /// + /// let mut iteration = Iteration::new(); + /// let variable = iteration.variable::<(usize, usize)>("source"); + /// variable.extend((0 .. 10).map(|x| (x, x + 1))); + /// variable.extend((0 .. 10).map(|x| (x + 1, x))); + /// + /// while iteration.changed() { + /// variable.from_join(&variable, &variable, |&key, &val1, &val2| (val1, val2)); + /// } + /// + /// let result = variable.complete(); + /// assert_eq!(result.len(), 121); + /// ``` + pub fn from_join<'me, K: Ord, V1: Ord, V2: Ord>( + &self, + input1: &'me Variable<(K, V1)>, + input2: impl JoinInput<'me, (K, V2)>, + logic: impl FnMut(&K, &V1, &V2) -> Tuple, + ) { + join::join_into(input1, input2, self, logic) + } + + /// Adds tuples from `input1` whose key is not present in `input2`. + /// + /// Note that `input1` must be a variable: if you have a relation + /// instead, you can use `Relation::from_antijoin` and then + /// `Variable::insert`. Note that the result will not vary during + /// the iteration. + /// + /// # Examples + /// + /// This example starts a collection with the pairs (x, x+1) for x in 0 .. 10. It then + /// adds any pairs (x+1,x) for which x is not a multiple of three. That excludes four + /// pairs (for 0, 3, 6, and 9) which should leave us with 16 total pairs. + /// + /// ``` + /// use datafrog::{Iteration, Relation}; + /// + /// let mut iteration = Iteration::new(); + /// let variable = iteration.variable::<(usize, usize)>("source"); + /// variable.extend((0 .. 10).map(|x| (x, x + 1))); + /// + /// let relation: Relation<_> = (0 .. 10).filter(|x| x % 3 == 0).collect(); + /// + /// while iteration.changed() { + /// variable.from_antijoin(&variable, &relation, |&key, &val| (val, key)); + /// } + /// + /// let result = variable.complete(); + /// assert_eq!(result.len(), 16); + /// ``` + pub fn from_antijoin<K: Ord, V: Ord>( + &self, + input1: &Variable<(K, V)>, + input2: &Relation<K>, + logic: impl FnMut(&K, &V) -> Tuple, + ) { + self.insert(join::antijoin(input1, input2, logic)) + } + + /// Adds tuples that result from mapping `input`. + /// + /// # Examples + /// + /// This example starts a collection with the pairs (x, x) for x in 0 .. 10. It then + /// repeatedly adds any pairs (x, z) for (x, y) in the collection, where z is the Collatz + /// step for y: it is y/2 if y is even, and 3*y + 1 if y is odd. This produces all of the + /// pairs (x, y) where x visits y as part of its Collatz journey. + /// + /// ``` + /// use datafrog::{Iteration, Relation}; + /// + /// let mut iteration = Iteration::new(); + /// let variable = iteration.variable::<(usize, usize)>("source"); + /// variable.extend((0 .. 10).map(|x| (x, x))); + /// + /// while iteration.changed() { + /// variable.from_map(&variable, |&(key, val)| + /// if val % 2 == 0 { + /// (key, val/2) + /// } + /// else { + /// (key, 3*val + 1) + /// }); + /// } + /// + /// let result = variable.complete(); + /// assert_eq!(result.len(), 74); + /// ``` + pub fn from_map<T2: Ord>(&self, input: &Variable<T2>, logic: impl FnMut(&T2) -> Tuple) { + map::map_into(input, self, logic) + } + + /// Adds tuples that result from combining `source` with the + /// relations given in `leapers`. This operation is very flexible + /// and can be used to do a combination of joins and anti-joins. + /// The main limitation is that the things being combined must + /// consist of one dynamic variable (`source`) and then several + /// fixed relations (`leapers`). + /// + /// The idea is as follows: + /// + /// - You will be inserting new tuples that result from joining (and anti-joining) + /// some dynamic variable `source` of source tuples (`SourceTuple`) + /// with some set of values (of type `Val`). + /// - You provide these values by combining `source` with a set of leapers + /// `leapers`, each of which is derived from a fixed relation. The `leapers` + /// should be either a single leaper (of suitable type) or else a tuple of leapers. + /// You can create a leaper in one of two ways: + /// - Extension: In this case, you have a relation of type `(K, Val)` for some + /// type `K`. You provide a closure that maps from `SourceTuple` to the key + /// `K`. If you use `relation.extend_with`, then any `Val` values the + /// relation provides will be added to the set of values; if you use + /// `extend_anti`, then the `Val` values will be removed. + /// - Filtering: In this case, you have a relation of type `K` for some + /// type `K` and you provide a closure that maps from `SourceTuple` to + /// the key `K`. Filters don't provide values but they remove source + /// tuples. + /// - Finally, you get a callback `logic` that accepts each `(SourceTuple, Val)` + /// that was successfully joined (and not filtered) and which maps to the + /// type of this variable. + pub fn from_leapjoin<'leap, SourceTuple: Ord, Val: Ord + 'leap>( + &self, + source: &Variable<SourceTuple>, + leapers: impl Leapers<'leap, SourceTuple, Val>, + logic: impl FnMut(&SourceTuple, &Val) -> Tuple, + ) { + self.insert(treefrog::leapjoin(&source.recent.borrow(), leapers, logic)); + } +} + +impl<Tuple: Ord> Clone for Variable<Tuple> { + fn clone(&self) -> Self { + Variable { + distinct: self.distinct, + name: self.name.clone(), + stable: self.stable.clone(), + recent: self.recent.clone(), + to_add: self.to_add.clone(), + } + } +} + +impl<Tuple: Ord> Variable<Tuple> { + fn new(name: &str) -> Self { + Variable { + distinct: true, + name: name.to_string(), + stable: Rc::new(RefCell::new(Vec::new())), + recent: Rc::new(RefCell::new(Vec::new().into())), + to_add: Rc::new(RefCell::new(Vec::new())), + } + } + + /// Inserts a relation into the variable. + /// + /// This is most commonly used to load initial values into a variable. + /// it is not obvious that it should be commonly used otherwise, but + /// it should not be harmful. + pub fn insert(&self, relation: Relation<Tuple>) { + if !relation.is_empty() { + self.to_add.borrow_mut().push(relation); + } + } + + /// Extend the variable with values from the iterator. + /// + /// This is most commonly used to load initial values into a variable. + /// it is not obvious that it should be commonly used otherwise, but + /// it should not be harmful. + pub fn extend<T>(&self, iterator: impl IntoIterator<Item = T>) + where + Relation<Tuple>: FromIterator<T>, + { + self.insert(iterator.into_iter().collect()); + } + + /// Consumes the variable and returns a relation. + /// + /// This method removes the ability for the variable to develop, and + /// flattens all internal tuples down to one relation. The method + /// asserts that iteration has completed, in that `self.recent` and + /// `self.to_add` should both be empty. + pub fn complete(self) -> Relation<Tuple> { + assert!(self.recent.borrow().is_empty()); + assert!(self.to_add.borrow().is_empty()); + let mut result: Relation<Tuple> = Vec::new().into(); + while let Some(batch) = self.stable.borrow_mut().pop() { + result = result.merge(batch); + } + result + } +} + +impl<Tuple: Ord> VariableTrait for Variable<Tuple> { + fn changed(&mut self) -> bool { + // 1. Merge self.recent into self.stable. + if !self.recent.borrow().is_empty() { + let mut recent = + ::std::mem::replace(&mut (*self.recent.borrow_mut()), Vec::new().into()); + while self + .stable + .borrow() + .last() + .map(|x| x.len() <= 2 * recent.len()) + == Some(true) + { + let last = self.stable.borrow_mut().pop().unwrap(); + recent = recent.merge(last); + } + self.stable.borrow_mut().push(recent); + } + + // 2. Move self.to_add into self.recent. + let to_add = self.to_add.borrow_mut().pop(); + if let Some(mut to_add) = to_add { + while let Some(to_add_more) = self.to_add.borrow_mut().pop() { + to_add = to_add.merge(to_add_more); + } + // 2b. Restrict `to_add` to tuples not in `self.stable`. + if self.distinct { + for batch in self.stable.borrow().iter() { + let mut slice = &batch[..]; + // Only gallop if the slice is relatively large. + if slice.len() > 4 * to_add.elements.len() { + to_add.elements.retain(|x| { + slice = join::gallop(slice, |y| y < x); + slice.is_empty() || &slice[0] != x + }); + } else { + to_add.elements.retain(|x| { + while !slice.is_empty() && &slice[0] < x { + slice = &slice[1..]; + } + slice.is_empty() || &slice[0] != x + }); + } + } + } + *self.recent.borrow_mut() = to_add; + } + + // let mut total = 0; + // for tuple in self.stable.borrow().iter() { + // total += tuple.len(); + // } + + // println!("Variable\t{}\t{}\t{}", self.name, total, self.recent.borrow().len()); + + !self.recent.borrow().is_empty() + } +} + +// impl<Tuple: Ord> Drop for Variable<Tuple> { +// fn drop(&mut self) { +// let mut total = 0; +// for batch in self.stable.borrow().iter() { +// total += batch.len(); +// } +// println!("FINAL: {:?}\t{:?}", self.name, total); +// } +// } diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/src/map.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/src/map.rs new file mode 100644 index 0000000..1a8c101 --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/src/map.rs @@ -0,0 +1,13 @@ +//! Map functionality. + +use super::{Relation, Variable}; + +pub(crate) fn map_into<T1: Ord, T2: Ord>( + input: &Variable<T1>, + output: &Variable<T2>, + logic: impl FnMut(&T1) -> T2, +) { + let results: Vec<T2> = input.recent.borrow().iter().map(logic).collect(); + + output.insert(Relation::from_vec(results)); +} diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/src/test.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/src/test.rs new file mode 100644 index 0000000..9d5af35 --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/src/test.rs @@ -0,0 +1,195 @@ +#![cfg(test)] + +use crate::Iteration; +use crate::Relation; +use crate::RelationLeaper; +use proptest::prelude::*; +use proptest::{proptest, proptest_helper}; + +fn inputs() -> impl Strategy<Value = Vec<(u32, u32)>> { + prop::collection::vec((0_u32..100, 0_u32..100), 1..500) +} + +/// The original way to use datafrog -- computes reachable nodes from a set of edges +fn reachable_with_var_join(edges: &[(u32, u32)]) -> Relation<(u32, u32)> { + let edges: Relation<_> = edges.iter().collect(); + let mut iteration = Iteration::new(); + + let edges_by_successor = iteration.variable::<(u32, u32)>("edges_invert"); + edges_by_successor.extend(edges.iter().map(|&(n1, n2)| (n2, n1))); + + let reachable = iteration.variable::<(u32, u32)>("reachable"); + reachable.insert(edges); + + while iteration.changed() { + // reachable(N1, N3) :- edges(N1, N2), reachable(N2, N3). + reachable.from_join(&reachable, &edges_by_successor, |&_, &n3, &n1| (n1, n3)); + } + + reachable.complete() +} + +/// Like `reachable`, but using a relation as an input to `from_join` +fn reachable_with_relation_join(edges: &[(u32, u32)]) -> Relation<(u32, u32)> { + let edges: Relation<_> = edges.iter().collect(); + let mut iteration = Iteration::new(); + + // NB. Changed from `reachable_with_var_join`: + let edges_by_successor: Relation<_> = edges.iter().map(|&(n1, n2)| (n2, n1)).collect(); + + let reachable = iteration.variable::<(u32, u32)>("reachable"); + reachable.insert(edges); + + while iteration.changed() { + // reachable(N1, N3) :- edges(N1, N2), reachable(N2, N3). + reachable.from_join(&reachable, &edges_by_successor, |&_, &n3, &n1| (n1, n3)); + } + + reachable.complete() +} + +fn reachable_with_leapfrog(edges: &[(u32, u32)]) -> Relation<(u32, u32)> { + let edges: Relation<_> = edges.iter().collect(); + let mut iteration = Iteration::new(); + + let edges_by_successor: Relation<_> = edges.iter().map(|&(n1, n2)| (n2, n1)).collect(); + + let reachable = iteration.variable::<(u32, u32)>("reachable"); + reachable.insert(edges); + + while iteration.changed() { + // reachable(N1, N3) :- edges(N1, N2), reachable(N2, N3). + reachable.from_leapjoin( + &reachable, + edges_by_successor.extend_with(|&(n2, _)| n2), + |&(_, n3), &n1| (n1, n3), + ); + } + + reachable.complete() +} + +/// Computes a join where the values are summed -- uses iteration +/// variables (the original datafrog technique). +fn sum_join_via_var( + input1_slice: &[(u32, u32)], + input2_slice: &[(u32, u32)], +) -> Relation<(u32, u32)> { + let mut iteration = Iteration::new(); + + let input1 = iteration.variable::<(u32, u32)>("input1"); + input1.extend(input1_slice); + + let input2 = iteration.variable::<(u32, u32)>("input1"); + input2.extend(input2_slice); + + let output = iteration.variable::<(u32, u32)>("output"); + + while iteration.changed() { + // output(K1, V1 * 100 + V2) :- input1(K1, V1), input2(K1, V2). + output.from_join(&input1, &input2, |&k1, &v1, &v2| (k1, v1 * 100 + v2)); + } + + output.complete() +} + +/// Computes a join where the values are summed -- uses iteration +/// variables (the original datafrog technique). +fn sum_join_via_relation( + input1_slice: &[(u32, u32)], + input2_slice: &[(u32, u32)], +) -> Relation<(u32, u32)> { + let input1: Relation<_> = input1_slice.iter().collect(); + let input2: Relation<_> = input2_slice.iter().collect(); + Relation::from_join(&input1, &input2, |&k1, &v1, &v2| (k1, v1 * 100 + v2)) +} + +proptest! { + #[test] + fn reachable_leapfrog_vs_var_join(edges in inputs()) { + let reachable1 = reachable_with_var_join(&edges); + let reachable2 = reachable_with_leapfrog(&edges); + assert_eq!(reachable1.elements, reachable2.elements); + } + + #[test] + fn reachable_rel_join_vs_var_join(edges in inputs()) { + let reachable1 = reachable_with_var_join(&edges); + let reachable2 = reachable_with_relation_join(&edges); + assert_eq!(reachable1.elements, reachable2.elements); + } + + #[test] + fn sum_join_from_var_vs_rel((set1, set2) in (inputs(), inputs())) { + let output1 = sum_join_via_var(&set1, &set2); + let output2 = sum_join_via_relation(&set1, &set2); + assert_eq!(output1.elements, output2.elements); + } + + /// Test the behavior of `filter_anti` used on its own in a + /// leapjoin -- effectively it becomes an "intersection" + /// operation. + #[test] + fn filter_with_on_its_own((set1, set2) in (inputs(), inputs())) { + let input1: Relation<(u32, u32)> = set1.iter().collect(); + let input2: Relation<(u32, u32)> = set2.iter().collect(); + let intersection1 = Relation::from_leapjoin( + &input1, + input2.filter_with(|&tuple| tuple), + |&tuple, &()| tuple, + ); + + let intersection2: Relation<(u32, u32)> = input1.elements.iter() + .filter(|t| input2.elements.binary_search(&t).is_ok()) + .collect(); + + assert_eq!(intersection1.elements, intersection2.elements); + } + + /// Test the behavior of `filter_anti` used on its own in a + /// leapjoin -- effectively it becomes a "set minus" operation. + #[test] + fn filter_anti_on_its_own((set1, set2) in (inputs(), inputs())) { + let input1: Relation<(u32, u32)> = set1.iter().collect(); + let input2: Relation<(u32, u32)> = set2.iter().collect(); + + let difference1 = Relation::from_leapjoin( + &input1, + input2.filter_anti(|&tuple| tuple), + |&tuple, &()| tuple, + ); + + let difference2: Relation<(u32, u32)> = input1.elements.iter() + .filter(|t| input2.elements.binary_search(&t).is_err()) + .collect(); + + assert_eq!(difference1.elements, difference2.elements); + } +} + +/// Test that `from_leapjoin` matches against the tuples from an +/// `extend` that precedes first iteration. +/// +/// This was always true, but wasn't immediately obvious to me until I +/// re-read the code more carefully. -nikomatsakis +#[test] +fn leapjoin_from_extend() { + let doubles: Relation<(u32, u32)> = (0..10).map(|i| (i, i * 2)).collect(); + + let mut iteration = Iteration::new(); + + let variable = iteration.variable::<(u32, u32)>("variable"); + variable.extend(Some((2, 2))); + + while iteration.changed() { + variable.from_leapjoin( + &variable, + doubles.extend_with(|&(i, _)| i), + |&(i, _), &j| (i, j), + ); + } + + let variable = variable.complete(); + + assert_eq!(variable.elements, vec![(2, 2), (2, 4)]); +} diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/src/treefrog.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/src/treefrog.rs new file mode 100644 index 0000000..2ad238f --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/src/treefrog.rs @@ -0,0 +1,661 @@ +//! Join functionality. + +use super::Relation; + +/// Performs treefrog leapjoin using a list of leapers. +pub(crate) fn leapjoin<'leap, Tuple: Ord, Val: Ord + 'leap, Result: Ord>( + source: &[Tuple], + mut leapers: impl Leapers<'leap, Tuple, Val>, + mut logic: impl FnMut(&Tuple, &Val) -> Result, +) -> Relation<Result> { + let mut result = Vec::new(); // temp output storage. + let mut values = Vec::new(); // temp value storage. + + for tuple in source { + // Determine which leaper would propose the fewest values. + let mut min_index = usize::max_value(); + let mut min_count = usize::max_value(); + leapers.for_each_count(tuple, |index, count| { + if min_count > count { + min_count = count; + min_index = index; + } + }); + + // We had best have at least one relation restricting values. + assert!(min_count < usize::max_value()); + + // If there are values to propose: + if min_count > 0 { + // Push the values that `min_index` "proposes" into `values`. + leapers.propose(tuple, min_index, &mut values); + + // Give other leapers a chance to remove values from + // anti-joins or filters. + leapers.intersect(tuple, min_index, &mut values); + + // Push remaining items into result. + for val in values.drain(..) { + result.push(logic(tuple, val)); + } + } + } + + Relation::from_vec(result) +} + +/// Implemented for a tuple of leapers +pub trait Leapers<'leap, Tuple, Val> { + /// Internal method: + fn for_each_count(&mut self, tuple: &Tuple, op: impl FnMut(usize, usize)); + + /// Internal method: + fn propose(&mut self, tuple: &Tuple, min_index: usize, values: &mut Vec<&'leap Val>); + + /// Internal method: + fn intersect(&mut self, tuple: &Tuple, min_index: usize, values: &mut Vec<&'leap Val>); +} + +macro_rules! tuple_leapers { + ($($Ty:ident)*) => { + #[allow(unused_assignments, non_snake_case)] + impl<'leap, Tuple, Val, $($Ty),*> Leapers<'leap, Tuple, Val> for ($($Ty,)*) + where + $($Ty: Leaper<'leap, Tuple, Val>,)* + { + fn for_each_count(&mut self, tuple: &Tuple, mut op: impl FnMut(usize, usize)) { + let ($($Ty,)*) = self; + let mut index = 0; + $( + let count = $Ty.count(tuple); + op(index, count); + index += 1; + )* + } + + fn propose(&mut self, tuple: &Tuple, min_index: usize, values: &mut Vec<&'leap Val>) { + let ($($Ty,)*) = self; + let mut index = 0; + $( + if min_index == index { + return $Ty.propose(tuple, values); + } + index += 1; + )* + panic!("no match found for min_index={}", min_index); + } + + fn intersect(&mut self, tuple: &Tuple, min_index: usize, values: &mut Vec<&'leap Val>) { + let ($($Ty,)*) = self; + let mut index = 0; + $( + if min_index != index { + $Ty.intersect(tuple, values); + } + index += 1; + )* + } + } + } +} + +tuple_leapers!(A B); +tuple_leapers!(A B C); +tuple_leapers!(A B C D); +tuple_leapers!(A B C D E); +tuple_leapers!(A B C D E F); +tuple_leapers!(A B C D E F G); + +/// Methods to support treefrog leapjoin. +pub trait Leaper<'leap, Tuple, Val> { + /// Estimates the number of proposed values. + fn count(&mut self, prefix: &Tuple) -> usize; + /// Populates `values` with proposed values. + fn propose(&mut self, prefix: &Tuple, values: &mut Vec<&'leap Val>); + /// Restricts `values` to proposed values. + fn intersect(&mut self, prefix: &Tuple, values: &mut Vec<&'leap Val>); +} + +pub(crate) mod filters { + use super::Leaper; + use super::Leapers; + + /// A treefrog leaper that tests each of the tuples from the main + /// input (the "prefix"). Use like `PrefixFilter::from(|tuple| + /// ...)`; if the closure returns true, then the tuple is + /// retained, else it will be ignored. This leaper can be used in + /// isolation in which case it just acts like a filter on the + /// input (the "proposed value" will be `()` type). + pub struct PrefixFilter<Tuple, Func: Fn(&Tuple) -> bool> { + phantom: ::std::marker::PhantomData<Tuple>, + predicate: Func, + } + + impl<'leap, Tuple, Func> PrefixFilter<Tuple, Func> + where + Func: Fn(&Tuple) -> bool, + { + /// Creates a new filter based on the prefix + pub fn from(predicate: Func) -> Self { + PrefixFilter { + phantom: ::std::marker::PhantomData, + predicate, + } + } + } + + impl<'leap, Tuple, Val, Func> Leaper<'leap, Tuple, Val> for PrefixFilter<Tuple, Func> + where + Func: Fn(&Tuple) -> bool, + { + /// Estimates the number of proposed values. + fn count(&mut self, prefix: &Tuple) -> usize { + if (self.predicate)(prefix) { + usize::max_value() + } else { + 0 + } + } + /// Populates `values` with proposed values. + fn propose(&mut self, _prefix: &Tuple, _values: &mut Vec<&'leap Val>) { + panic!("PrefixFilter::propose(): variable apparently unbound"); + } + /// Restricts `values` to proposed values. + fn intersect(&mut self, _prefix: &Tuple, _values: &mut Vec<&'leap Val>) { + // We can only be here if we returned max_value() above. + } + } + + impl<'leap, Tuple, Func> Leapers<'leap, Tuple, ()> for PrefixFilter<Tuple, Func> + where + Func: Fn(&Tuple) -> bool, + { + fn for_each_count(&mut self, tuple: &Tuple, mut op: impl FnMut(usize, usize)) { + if <Self as Leaper<'_, Tuple, ()>>::count(self, tuple) == 0 { + op(0, 0) + } else { + // we will "propose" the `()` value if the predicate applies + op(0, 1) + } + } + + fn propose(&mut self, _: &Tuple, min_index: usize, values: &mut Vec<&'leap ()>) { + assert_eq!(min_index, 0); + values.push(&()); + } + + fn intersect(&mut self, _: &Tuple, min_index: usize, values: &mut Vec<&'leap ()>) { + assert_eq!(min_index, 0); + assert_eq!(values.len(), 1); + } + } + + /// A treefrog leaper based on a predicate of prefix and value. + /// Use like `ValueFilter::from(|tuple, value| ...)`. The closure + /// should return true if `value` ought to be retained. The + /// `value` will be a value proposed elsewhere by an `extend_with` + /// leaper. + /// + /// This leaper cannot be used in isolation, it must be combined + /// with other leapers. + pub struct ValueFilter<Tuple, Val, Func: Fn(&Tuple, &Val) -> bool> { + phantom: ::std::marker::PhantomData<(Tuple, Val)>, + predicate: Func, + } + + impl<'leap, Tuple, Val, Func> ValueFilter<Tuple, Val, Func> + where + Func: Fn(&Tuple, &Val) -> bool, + { + /// Creates a new filter based on the prefix + pub fn from(predicate: Func) -> Self { + ValueFilter { + phantom: ::std::marker::PhantomData, + predicate, + } + } + } + + impl<'leap, Tuple, Val, Func> Leaper<'leap, Tuple, Val> for ValueFilter<Tuple, Val, Func> + where + Func: Fn(&Tuple, &Val) -> bool, + { + /// Estimates the number of proposed values. + fn count(&mut self, _prefix: &Tuple) -> usize { + usize::max_value() + } + /// Populates `values` with proposed values. + fn propose(&mut self, _prefix: &Tuple, _values: &mut Vec<&'leap Val>) { + panic!("PrefixFilter::propose(): variable apparently unbound"); + } + /// Restricts `values` to proposed values. + fn intersect(&mut self, prefix: &Tuple, values: &mut Vec<&'leap Val>) { + values.retain(|val| (self.predicate)(prefix, val)); + } + } + +} + +/// Extension method for relations. +pub trait RelationLeaper<Key: Ord, Val: Ord> { + /// Extend with `Val` using the elements of the relation. + fn extend_with<'leap, Tuple: Ord, Func: Fn(&Tuple) -> Key>( + &'leap self, + key_func: Func, + ) -> extend_with::ExtendWith<'leap, Key, Val, Tuple, Func> + where + Key: 'leap, + Val: 'leap; + /// Extend with `Val` using the complement of the relation. + fn extend_anti<'leap, Tuple: Ord, Func: Fn(&Tuple) -> Key>( + &'leap self, + key_func: Func, + ) -> extend_anti::ExtendAnti<'leap, Key, Val, Tuple, Func> + where + Key: 'leap, + Val: 'leap; + /// Extend with any value if tuple is present in relation. + fn filter_with<'leap, Tuple: Ord, Func: Fn(&Tuple) -> (Key, Val)>( + &'leap self, + key_func: Func, + ) -> filter_with::FilterWith<'leap, Key, Val, Tuple, Func> + where + Key: 'leap, + Val: 'leap; + /// Extend with any value if tuple is absent from relation. + fn filter_anti<'leap, Tuple: Ord, Func: Fn(&Tuple) -> (Key, Val)>( + &'leap self, + key_func: Func, + ) -> filter_anti::FilterAnti<'leap, Key, Val, Tuple, Func> + where + Key: 'leap, + Val: 'leap; +} + +impl<Key: Ord, Val: Ord> RelationLeaper<Key, Val> for Relation<(Key, Val)> { + fn extend_with<'leap, Tuple: Ord, Func: Fn(&Tuple) -> Key>( + &'leap self, + key_func: Func, + ) -> extend_with::ExtendWith<'leap, Key, Val, Tuple, Func> + where + Key: 'leap, + Val: 'leap, + { + extend_with::ExtendWith::from(self, key_func) + } + fn extend_anti<'leap, Tuple: Ord, Func: Fn(&Tuple) -> Key>( + &'leap self, + key_func: Func, + ) -> extend_anti::ExtendAnti<'leap, Key, Val, Tuple, Func> + where + Key: 'leap, + Val: 'leap, + { + extend_anti::ExtendAnti::from(self, key_func) + } + fn filter_with<'leap, Tuple: Ord, Func: Fn(&Tuple) -> (Key, Val)>( + &'leap self, + key_func: Func, + ) -> filter_with::FilterWith<'leap, Key, Val, Tuple, Func> + where + Key: 'leap, + Val: 'leap, + { + filter_with::FilterWith::from(self, key_func) + } + fn filter_anti<'leap, Tuple: Ord, Func: Fn(&Tuple) -> (Key, Val)>( + &'leap self, + key_func: Func, + ) -> filter_anti::FilterAnti<'leap, Key, Val, Tuple, Func> + where + Key: 'leap, + Val: 'leap, + { + filter_anti::FilterAnti::from(self, key_func) + } +} + +pub(crate) mod extend_with { + use super::{binary_search, Leaper, Leapers, Relation}; + use crate::join::gallop; + + /// Wraps a Relation<Tuple> as a leaper. + pub struct ExtendWith<'leap, Key, Val, Tuple, Func> + where + Key: Ord + 'leap, + Val: Ord + 'leap, + Tuple: Ord, + Func: Fn(&Tuple) -> Key, + { + relation: &'leap Relation<(Key, Val)>, + start: usize, + end: usize, + key_func: Func, + phantom: ::std::marker::PhantomData<Tuple>, + } + + impl<'leap, Key, Val, Tuple, Func> ExtendWith<'leap, Key, Val, Tuple, Func> + where + Key: Ord + 'leap, + Val: Ord + 'leap, + Tuple: Ord, + Func: Fn(&Tuple) -> Key, + { + /// Constructs a ExtendWith from a relation and key and value function. + pub fn from(relation: &'leap Relation<(Key, Val)>, key_func: Func) -> Self { + ExtendWith { + relation, + start: 0, + end: 0, + key_func, + phantom: ::std::marker::PhantomData, + } + } + } + + impl<'leap, Key, Val, Tuple, Func> Leaper<'leap, Tuple, Val> + for ExtendWith<'leap, Key, Val, Tuple, Func> + where + Key: Ord + 'leap, + Val: Ord + 'leap, + Tuple: Ord, + Func: Fn(&Tuple) -> Key, + { + fn count(&mut self, prefix: &Tuple) -> usize { + let key = (self.key_func)(prefix); + self.start = binary_search(&self.relation[..], |x| &x.0 < &key); + let slice1 = &self.relation[self.start..]; + let slice2 = gallop(slice1, |x| &x.0 <= &key); + self.end = self.relation.len() - slice2.len(); + slice1.len() - slice2.len() + } + fn propose(&mut self, _prefix: &Tuple, values: &mut Vec<&'leap Val>) { + let slice = &self.relation[self.start..self.end]; + values.extend(slice.iter().map(|&(_, ref val)| val)); + } + fn intersect(&mut self, _prefix: &Tuple, values: &mut Vec<&'leap Val>) { + let mut slice = &self.relation[self.start..self.end]; + values.retain(|v| { + slice = gallop(slice, |kv| &kv.1 < v); + slice.get(0).map(|kv| &kv.1) == Some(v) + }); + } + } + + impl<'leap, Key, Val, Tuple, Func> Leapers<'leap, Tuple, Val> + for ExtendWith<'leap, Key, Val, Tuple, Func> + where + Key: Ord + 'leap, + Val: Ord + 'leap, + Tuple: Ord, + Func: Fn(&Tuple) -> Key, + { + fn for_each_count(&mut self, tuple: &Tuple, mut op: impl FnMut(usize, usize)) { + op(0, self.count(tuple)) + } + + fn propose(&mut self, tuple: &Tuple, min_index: usize, values: &mut Vec<&'leap Val>) { + assert_eq!(min_index, 0); + Leaper::propose(self, tuple, values); + } + + fn intersect(&mut self, _: &Tuple, min_index: usize, _: &mut Vec<&'leap Val>) { + assert_eq!(min_index, 0); + } + } +} + +pub(crate) mod extend_anti { + use super::{binary_search, Leaper, Relation}; + use crate::join::gallop; + + /// Wraps a Relation<Tuple> as a leaper. + pub struct ExtendAnti<'leap, Key, Val, Tuple, Func> + where + Key: Ord + 'leap, + Val: Ord + 'leap, + Tuple: Ord, + Func: Fn(&Tuple) -> Key, + { + relation: &'leap Relation<(Key, Val)>, + key_func: Func, + phantom: ::std::marker::PhantomData<Tuple>, + } + + impl<'leap, Key, Val, Tuple, Func> ExtendAnti<'leap, Key, Val, Tuple, Func> + where + Key: Ord + 'leap, + Val: Ord + 'leap, + Tuple: Ord, + Func: Fn(&Tuple) -> Key, + { + /// Constructs a ExtendAnti from a relation and key and value function. + pub fn from(relation: &'leap Relation<(Key, Val)>, key_func: Func) -> Self { + ExtendAnti { + relation, + key_func, + phantom: ::std::marker::PhantomData, + } + } + } + + impl<'leap, Key: Ord, Val: Ord + 'leap, Tuple: Ord, Func> Leaper<'leap, Tuple, Val> + for ExtendAnti<'leap, Key, Val, Tuple, Func> + where + Key: Ord + 'leap, + Val: Ord + 'leap, + Tuple: Ord, + Func: Fn(&Tuple) -> Key, + { + fn count(&mut self, _prefix: &Tuple) -> usize { + usize::max_value() + } + fn propose(&mut self, _prefix: &Tuple, _values: &mut Vec<&'leap Val>) { + panic!("ExtendAnti::propose(): variable apparently unbound."); + } + fn intersect(&mut self, prefix: &Tuple, values: &mut Vec<&'leap Val>) { + let key = (self.key_func)(prefix); + let start = binary_search(&self.relation[..], |x| &x.0 < &key); + let slice1 = &self.relation[start..]; + let slice2 = gallop(slice1, |x| &x.0 <= &key); + let mut slice = &slice1[..(slice1.len() - slice2.len())]; + if !slice.is_empty() { + values.retain(|v| { + slice = gallop(slice, |kv| &kv.1 < v); + slice.get(0).map(|kv| &kv.1) != Some(v) + }); + } + } + } +} + +pub(crate) mod filter_with { + + use super::{Leaper, Leapers, Relation}; + + /// Wraps a Relation<Tuple> as a leaper. + pub struct FilterWith<'leap, Key, Val, Tuple, Func> + where + Key: Ord + 'leap, + Val: Ord + 'leap, + Tuple: Ord, + Func: Fn(&Tuple) -> (Key, Val), + { + relation: &'leap Relation<(Key, Val)>, + key_func: Func, + phantom: ::std::marker::PhantomData<Tuple>, + } + + impl<'leap, Key, Val, Tuple, Func> FilterWith<'leap, Key, Val, Tuple, Func> + where + Key: Ord + 'leap, + Val: Ord + 'leap, + Tuple: Ord, + Func: Fn(&Tuple) -> (Key, Val), + { + /// Constructs a FilterWith from a relation and key and value function. + pub fn from(relation: &'leap Relation<(Key, Val)>, key_func: Func) -> Self { + FilterWith { + relation, + key_func, + phantom: ::std::marker::PhantomData, + } + } + } + + impl<'leap, Key, Val, Val2, Tuple, Func> Leaper<'leap, Tuple, Val2> + for FilterWith<'leap, Key, Val, Tuple, Func> + where + Key: Ord + 'leap, + Val: Ord + 'leap, + Tuple: Ord, + Func: Fn(&Tuple) -> (Key, Val), + { + fn count(&mut self, prefix: &Tuple) -> usize { + let key_val = (self.key_func)(prefix); + if self.relation.binary_search(&key_val).is_ok() { + usize::max_value() + } else { + 0 + } + } + fn propose(&mut self, _prefix: &Tuple, _values: &mut Vec<&'leap Val2>) { + panic!("FilterWith::propose(): variable apparently unbound."); + } + fn intersect(&mut self, _prefix: &Tuple, _values: &mut Vec<&'leap Val2>) { + // Only here because we didn't return zero above, right? + } + } + + impl<'leap, Key, Val, Tuple, Func> Leapers<'leap, Tuple, ()> + for FilterWith<'leap, Key, Val, Tuple, Func> + where + Key: Ord + 'leap, + Val: Ord + 'leap, + Tuple: Ord, + Func: Fn(&Tuple) -> (Key, Val), + { + fn for_each_count(&mut self, tuple: &Tuple, mut op: impl FnMut(usize, usize)) { + if <Self as Leaper<Tuple, ()>>::count(self, tuple) == 0 { + op(0, 0) + } else { + op(0, 1) + } + } + + fn propose(&mut self, _: &Tuple, min_index: usize, values: &mut Vec<&'leap ()>) { + assert_eq!(min_index, 0); + values.push(&()); + } + + fn intersect(&mut self, _: &Tuple, min_index: usize, values: &mut Vec<&'leap ()>) { + assert_eq!(min_index, 0); + assert_eq!(values.len(), 1); + } + } +} + +pub(crate) mod filter_anti { + + use super::{Leaper, Leapers, Relation}; + + /// Wraps a Relation<Tuple> as a leaper. + pub struct FilterAnti<'leap, Key, Val, Tuple, Func> + where + Key: Ord + 'leap, + Val: Ord + 'leap, + Tuple: Ord, + Func: Fn(&Tuple) -> (Key, Val), + { + relation: &'leap Relation<(Key, Val)>, + key_func: Func, + phantom: ::std::marker::PhantomData<Tuple>, + } + + impl<'leap, Key, Val, Tuple, Func> FilterAnti<'leap, Key, Val, Tuple, Func> + where + Key: Ord + 'leap, + Val: Ord + 'leap, + Tuple: Ord, + Func: Fn(&Tuple) -> (Key, Val), + { + /// Constructs a FilterAnti from a relation and key and value function. + pub fn from(relation: &'leap Relation<(Key, Val)>, key_func: Func) -> Self { + FilterAnti { + relation, + key_func, + phantom: ::std::marker::PhantomData, + } + } + } + + impl<'leap, Key: Ord, Val: Ord + 'leap, Val2, Tuple: Ord, Func> Leaper<'leap, Tuple, Val2> + for FilterAnti<'leap, Key, Val, Tuple, Func> + where + Key: Ord + 'leap, + Val: Ord + 'leap, + Tuple: Ord, + Func: Fn(&Tuple) -> (Key, Val), + { + fn count(&mut self, prefix: &Tuple) -> usize { + let key_val = (self.key_func)(prefix); + if self.relation.binary_search(&key_val).is_ok() { + 0 + } else { + usize::max_value() + } + } + fn propose(&mut self, _prefix: &Tuple, _values: &mut Vec<&'leap Val2>) { + panic!("FilterAnti::propose(): variable apparently unbound."); + } + fn intersect(&mut self, _prefix: &Tuple, _values: &mut Vec<&'leap Val2>) { + // Only here because we didn't return zero above, right? + } + } + + impl<'leap, Key, Val, Tuple, Func> Leapers<'leap, Tuple, ()> + for FilterAnti<'leap, Key, Val, Tuple, Func> + where + Key: Ord + 'leap, + Val: Ord + 'leap, + Tuple: Ord, + Func: Fn(&Tuple) -> (Key, Val), + { + fn for_each_count(&mut self, tuple: &Tuple, mut op: impl FnMut(usize, usize)) { + if <Self as Leaper<Tuple, ()>>::count(self, tuple) == 0 { + op(0, 0) + } else { + op(0, 1) + } + } + + fn propose(&mut self, _: &Tuple, min_index: usize, values: &mut Vec<&'leap ()>) { + // We only get here if `tuple` is *not* a member of `self.relation` + assert_eq!(min_index, 0); + values.push(&()); + } + + fn intersect(&mut self, _: &Tuple, min_index: usize, values: &mut Vec<&'leap ()>) { + // We only get here if `tuple` is not a member of `self.relation` + assert_eq!(min_index, 0); + assert_eq!(values.len(), 1); + } + } +} + +fn binary_search<T>(slice: &[T], mut cmp: impl FnMut(&T) -> bool) -> usize { + // we maintain the invariant that `lo` many elements of `slice` satisfy `cmp`. + // `hi` is maintained at the first element we know does not satisfy `cmp`. + + let mut hi = slice.len(); + let mut lo = 0; + while lo < hi { + let mid = lo + (hi - lo) / 2; + if cmp(&slice[mid]) { + lo = mid + 1; + } else { + hi = mid; + } + } + lo +} diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/.cargo-checksum.json b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/.cargo-checksum.json new file mode 100644 index 0000000..42ea021 --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"df7d7ea4256611dd5e3bf160e39bb3f8b665c6805ae47fdbf28acf9f77245ffd","Cargo.toml":"2161251dd0dfbea680a9d5fd762973e343fc5215794681c5ffd641faab9a4e4c","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"a23bbe55ac94081711c081a63df10d324a8a26f4b836952cb3c45c9318a03152","benches/value.rs":"b613ff353d3cf0ef8cb98e4ca461ea929b8ba553fe299f2eb2942d77a5b1b6a0","src/__private_api.rs":"da677f1e29e3cb135c971247031bc0eb20324294ab5c1c74c5118f87e45518ae","src/kv/error.rs":"6dae12424164c33b93915f5e70bd6d99d616c969c8bfb543806721dd9b423981","src/kv/key.rs":"9439e91c3ab3f9574a6a11a0347c7b63fdf1652384a6b28411136e4373de2970","src/kv/mod.rs":"3521a5bcfd7f92dcfac6c3c948020d686fee696596c566333a27edbbcc8a4ea8","src/kv/source.rs":"73fbc180c824072d86f1f41f8c59c014db1d8988a86be38a9128d67d6aab06a5","src/kv/value.rs":"0aade52b8e3523a17d6114f8b664793862032a94ea1ee2a4f12a20dd729b92d4","src/lib.rs":"55c32130cd8b99cde2ea962a403cdade52d20e80088357ba2784ee53b2eb9a2c","src/macros.rs":"dfb98017d5f205fec632069ab857a18661d6d563cf5162eeef64d367cc3ad7f5","src/serde.rs":"35f520f62fdba0216ccee33e5b66ad8f81dee3af5b65b824f1816180c9350df5","triagebot.toml":"a135e10c777cd13459559bdf74fb704c1379af7c9b0f70bc49fa6f5a837daa81"},"package":"a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"}
\ No newline at end of file diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/CHANGELOG.md b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/CHANGELOG.md new file mode 100644 index 0000000..2c89834 --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/CHANGELOG.md @@ -0,0 +1,324 @@ +# Change Log + +## [Unreleased] + +## [0.4.22] - 2024-06-27 + +## What's Changed +* Add some clarifications to the library docs by @KodrAus in https://github.com/rust-lang/log/pull/620 +* Add links to `colog` crate by @chrivers in https://github.com/rust-lang/log/pull/621 +* adding line_number test + updating some testing infrastructure by @DIvkov575 in https://github.com/rust-lang/log/pull/619 +* Clarify the actual set of functions that can race in _racy variants by @KodrAus in https://github.com/rust-lang/log/pull/623 +* Replace deprecated std::sync::atomic::spin_loop_hint() by @Catamantaloedis in https://github.com/rust-lang/log/pull/625 +* Check usage of max_level features by @Thomasdezeeuw in https://github.com/rust-lang/log/pull/627 +* Remove unneeded import by @Thomasdezeeuw in https://github.com/rust-lang/log/pull/628 +* Loosen orderings for logger initialization in https://github.com/rust-lang/log/pull/632. Originally by @pwoolcoc in https://github.com/rust-lang/log/pull/599 +* Use Location::caller() for file and line info in https://github.com/rust-lang/log/pull/633. Originally by @Cassy343 in https://github.com/rust-lang/log/pull/520 + +## New Contributors +* @chrivers made their first contribution in https://github.com/rust-lang/log/pull/621 +* @DIvkov575 made their first contribution in https://github.com/rust-lang/log/pull/619 +* @Catamantaloedis made their first contribution in https://github.com/rust-lang/log/pull/625 + +**Full Changelog**: https://github.com/rust-lang/log/compare/0.4.21...0.4.22 + +## [0.4.21] - 2024-02-27 + +## What's Changed +* Minor clippy nits by @nyurik in https://github.com/rust-lang/log/pull/578 +* Simplify Display impl by @nyurik in https://github.com/rust-lang/log/pull/579 +* Set all crates to 2021 edition by @nyurik in https://github.com/rust-lang/log/pull/580 +* Various changes based on review by @Thomasdezeeuw in https://github.com/rust-lang/log/pull/583 +* Fix typo in file_static() method doc by @dimo414 in https://github.com/rust-lang/log/pull/590 +* Specialize empty key value pairs by @EFanZh in https://github.com/rust-lang/log/pull/576 +* Fix incorrect lifetime in Value::to_str() by @peterjoel in https://github.com/rust-lang/log/pull/587 +* Remove some API of the key-value feature by @Thomasdezeeuw in https://github.com/rust-lang/log/pull/585 +* Add logcontrol-log and log-reload by @swsnr in https://github.com/rust-lang/log/pull/595 +* Add Serialization section to kv::Value docs by @Thomasdezeeuw in https://github.com/rust-lang/log/pull/593 +* Rename Value::to_str to to_cow_str by @Thomasdezeeuw in https://github.com/rust-lang/log/pull/592 +* Clarify documentation and simplify initialization of `STATIC_MAX_LEVEL` by @ptosi in https://github.com/rust-lang/log/pull/594 +* Update docs to 2021 edition, test by @nyurik in https://github.com/rust-lang/log/pull/577 +* Add "alterable_logger" link to README.md by @brummer-simon in https://github.com/rust-lang/log/pull/589 +* Normalize line ending by @EFanZh in https://github.com/rust-lang/log/pull/602 +* Remove `ok_or` in favor of `Option::ok_or` by @AngelicosPhosphoros in https://github.com/rust-lang/log/pull/607 +* Use `Acquire` ordering for initialization check by @AngelicosPhosphoros in https://github.com/rust-lang/log/pull/610 +* Get structured logging API ready for stabilization by @KodrAus in https://github.com/rust-lang/log/pull/613 + +## New Contributors +* @nyurik made their first contribution in https://github.com/rust-lang/log/pull/578 +* @dimo414 made their first contribution in https://github.com/rust-lang/log/pull/590 +* @peterjoel made their first contribution in https://github.com/rust-lang/log/pull/587 +* @ptosi made their first contribution in https://github.com/rust-lang/log/pull/594 +* @brummer-simon made their first contribution in https://github.com/rust-lang/log/pull/589 +* @AngelicosPhosphoros made their first contribution in https://github.com/rust-lang/log/pull/607 + +## [0.4.20] - 2023-07-11 + +* Remove rustversion dev-dependency by @Thomasdezeeuw in https://github.com/rust-lang/log/pull/568 +* Remove `local_inner_macros` usage by @EFanZh in https://github.com/rust-lang/log/pull/570 + +## [0.4.19] - 2023-06-10 + +* Use target_has_atomic instead of the old atomic_cas cfg by @GuillaumeGomez in https://github.com/rust-lang/log/pull/555 +* Put MSRV into Cargo.toml by @est31 in https://github.com/rust-lang/log/pull/557 + +## [0.4.18] - 2023-05-28 + +* fix markdown links (again) by @hellow554 in https://github.com/rust-lang/log/pull/513 +* add cargo doc to workflow by @hellow554 in https://github.com/rust-lang/log/pull/515 +* Apply Clippy lints by @hellow554 in https://github.com/rust-lang/log/pull/516 +* Replace ad-hoc eq_ignore_ascii_case with slice::eq_ignore_ascii_case by @glandium in https://github.com/rust-lang/log/pull/519 +* fix up windows targets by @KodrAus in https://github.com/rust-lang/log/pull/528 +* typo fix by @jiangying000 in https://github.com/rust-lang/log/pull/529 +* Remove dependency on cfg_if by @EriKWDev in https://github.com/rust-lang/log/pull/536 +* GitHub Workflows security hardening by @sashashura in https://github.com/rust-lang/log/pull/538 +* Fix build status badge by @atouchet in https://github.com/rust-lang/log/pull/539 +* Add call_logger to the documentation by @a1ecbr0wn in https://github.com/rust-lang/log/pull/547 +* Use stable internals for key-value API by @KodrAus in https://github.com/rust-lang/log/pull/550 +* Change wording of list of implementations by @Thomasdezeeuw in https://github.com/rust-lang/log/pull/553 +* Add std-logger to list of implementations by @Thomasdezeeuw in https://github.com/rust-lang/log/pull/554 +* Add `set_max_level_racy` and gate `set_max_level` by @djkoloski in https://github.com/rust-lang/log/pull/544 +* [doc] src/lib.rs : prefix an unused variable with an underscore by @OccupyMars2025 in https://github.com/rust-lang/log/pull/561 +* [doc] src/macros.rs : correct grammar errors of an example in lib documentation by @OccupyMars2025 in https://github.com/rust-lang/log/pull/562 + +## [0.4.17] - 2022-04-29 + +* Update `kv_unstable` internal dependencies. + +## [0.4.16] - 2022-03-22 + +* Fix a conflict with unqualified `Option` use in macros. + +## [0.4.15] - 2022-02-23 + +* Silence a warning about the deprecated `spin_loop_hint`. +* Relax ordering in the atomic `set_max_level` call. +* Add thumbv4t-none-eabi to targets that don't support atomics +* Allow levels to be iterated over. +* Implement `Log` on some common wrapper types. +* Improvements to test coverage. +* Improvements to documentation. +* Add key-value support to the `log!` macros. +* Tighten `kv_unstable` internal dependencies so they don't bump past their current alpha. +* Add a simple visit API to `kv_unstable`. +* Support `NonZero*` integers as values in structured logging +* Support static strings as keys in structured logging + +## [0.4.14] - 2021-01-27 + +* Remove the `__private_api_log_lit` special case. +* Fixed incorrect combination of `kv_unstable` and `std` features causing compile failures. +* Remove unstable `Value::to_*` conversions that were incorrectly using `as`. +* Rename unstable `Value::to_error` to `Value::to_borrowed_error`. + +## [0.4.13] - 2021-01-11 + +* This is the same as `0.4.11`, except with a `kv_unstable_std` feature added to aid migrating current dependents to `0.4.14` (which was originally going to be `0.4.13` until it was decided to create a patch from `0.4.11` to minimize disruption). + +## [0.4.12] - 2020-12-24 + +### New + +* Support platforms without atomics by racing instead of failing to compile +* Implement `Log` for `Box<T: Log>` +* Update `cfg-if` to `1.0` +* Internal reworks of the structured logging API. Removed the `Fill` API +and added `source::as_map` and `source::as_list` to easily serialize a `Source` +as either a map of `{key: value, ..}` or as a list of `[(key, value), ..]`. + +### Fixed + +* Fixed deserialization of `LevelFilter` to use their `u64` index variants + +## [0.4.11] - 2020-07-09 + +### New + +* Support coercing structured values into concrete types. +* Reference the `win_dbg_logger` in the readme. + +### Fixed + +* Updates a few deprecated items used internally. +* Fixed issues in docs and expands sections. +* Show the correct build badge in the readme. +* Fix up a possible inference breakage with structured value errors. +* Respect formatting flags in structured value formatting. + +## [0.4.10] - 2019-12-16 (yanked) + +### Fixed + +* Fixed the `log!` macros so they work in expression context (this regressed in `0.4.9`, which has been yanked). + +## [0.4.9] - 2019-12-12 (yanked) + +### Minimum Supported Rust Version + +This release bumps the minimum compiler version to `1.31.0`. This was mainly needed for `cfg-if`, +but between `1.16.0` and `1.31.0` there are a lot of language and library improvements we now +take advantage of. + +### New + +* Unstable support for capturing key-value pairs in a record using the `log!` macros + +### Improved + +* Better documentation for max level filters. +* Internal updates to line up with bumped MSRV + +## [0.4.8] - 2019-07-28 + +### New + +* Support attempting to get `Record` fields as static strings. + +## [0.4.7] - 2019-07-06 + +### New + +* Support for embedded environments with thread-unsafe initialization. +* Initial unstable support for capturing structured data under the `kv_unstable` +feature gate. This new API doesn't affect existing users and may change in future +patches (so those changes may not appear in the changelog until it stabilizes). + +### Improved + +* Docs for using `log` with the 2018 edition. +* Error messages for macros missing arguments. + +## [0.4.6] - 2018-10-27 + +### Improved + +* Support 2018-style macro import for the `log_enabled!` macro. + +## [0.4.5] - 2018-09-03 + +### Improved + +* Make `log`'s internal helper macros less likely to conflict with user-defined + macros. + +## [0.4.4] - 2018-08-17 + +### Improved + +* Support 2018-style imports of the log macros. + +## [0.4.3] - 2018-06-29 + +### Improved + +* More code generation improvements. + +## [0.4.2] - 2018-06-05 + +### Improved + +* Log invocations now generate less code. + +### Fixed + +* Example Logger implementations now properly set the max log level. + +## [0.4.1] - 2017-12-30 + +### Fixed + +* Some doc links were fixed. + +## [0.4.0] - 2017-12-24 + +The changes in this release include cleanup of some obscure functionality and a more robust public +API designed to support bridges to other logging systems, and provide more flexibility to new +features in the future. + +### Compatibility + +Vast portions of the Rust ecosystem use the 0.3.x release series of log, and we don't want to force +the community to go through the pain of upgrading every crate to 0.4.x at the exact same time. Along +with 0.4.0, we've published a new 0.3.9 release which acts as a "shim" over 0.4.0. This will allow +crates using either version to coexist without losing messages from one side or the other. + +There is one caveat - a log message generated by a crate using 0.4.x but consumed by a logging +implementation using 0.3.x will not have a file name or module path. Applications affected by this +can upgrade their logging implementations to one using 0.4.x to avoid losing this information. The +other direction does not lose any information, fortunately! + +**TL;DR** Libraries should feel comfortable upgrading to 0.4.0 without treating that as a breaking +change. Applications may need to update their logging implementation (e.g. env-logger) to a newer +version using log 0.4.x to avoid losing module and file information. + +### New + +* The crate is now `no_std` by default. +* `Level` and `LevelFilter` now implement `Serialize` and `Deserialize` when the `serde` feature is + enabled. +* The `Record` and `Metadata` types can now be constructed by third-party code via a builder API. +* The `logger` free function returns a reference to the logger implementation. This, along with the + ability to construct `Record`s, makes it possible to bridge from another logging framework to + this one without digging into the private internals of the crate. The standard `error!` `warn!`, + etc, macros now exclusively use the public API of the crate rather than "secret" internal APIs. +* `Log::flush` has been added to allow crates to tell the logging implementation to ensure that all + "in flight" log events have been persisted. This can be used, for example, just before an + application exits to ensure that asynchronous log sinks finish their work. + +### Removed + +* The `shutdown` and `shutdown_raw` functions have been removed. Supporting shutdown significantly + complicated the implementation and imposed a performance cost on each logging operation. +* The `log_panics` function and its associated `nightly` Cargo feature have been removed. Use the + [log-panics](https://crates.io/crates/log-panics) instead. + +### Changed + +* The `Log` prefix has been removed from type names. For example, `LogLevelFilter` is now + `LevelFilter`, and `LogRecord` is now `Record`. +* The `MaxLogLevelFilter` object has been removed in favor of a `set_max_level` free function. +* The `set_logger` free functions have been restructured. The logger is now directly passed to the + functions rather than a closure which returns the logger. `set_logger` now takes a `&'static + Log` and is usable in `no_std` contexts in place of the old `set_logger_raw`. `set_boxed_logger` + is a convenience function which takes a `Box<Log>` but otherwise acts like `set_logger`. It + requires the `std` feature. +* The `file` and `module_path` values in `Record` no longer have the `'static` lifetime to support + integration with other logging frameworks that don't provide a `'static` lifetime for the + equivalent values. +* The `file`, `line`, and `module_path` values in `Record` are now `Option`s to support integration + with other logging frameworks that don't provide those values. + +### In the Future + +* We're looking to add support for *structured* logging - the inclusion of extra key-value pairs of + information in a log event in addition to the normal string message. This should be able to be + added in a backwards compatible manner to the 0.4.x series when the design is worked out. + +## Older + +Look at the [release tags] for information about older releases. + +[Unreleased]: https://github.com/rust-lang-nursery/log/compare/0.4.21...HEAD +[0.4.21]: https://github.com/rust-lang/log/compare/0.4.20...0.4.21 +[0.4.20]: https://github.com/rust-lang-nursery/log/compare/0.4.19...0.4.20 +[0.4.19]: https://github.com/rust-lang-nursery/log/compare/0.4.18...0.4.19 +[0.4.18]: https://github.com/rust-lang-nursery/log/compare/0.4.17...0.4.18 +[0.4.17]: https://github.com/rust-lang-nursery/log/compare/0.4.16...0.4.17 +[0.4.16]: https://github.com/rust-lang-nursery/log/compare/0.4.15...0.4.16 +[0.4.15]: https://github.com/rust-lang-nursery/log/compare/0.4.13...0.4.15 +[0.4.14]: https://github.com/rust-lang-nursery/log/compare/0.4.13...0.4.14 +[0.4.13]: https://github.com/rust-lang-nursery/log/compare/0.4.11...0.4.13 +[0.4.12]: https://github.com/rust-lang-nursery/log/compare/0.4.11...0.4.12 +[0.4.11]: https://github.com/rust-lang-nursery/log/compare/0.4.10...0.4.11 +[0.4.10]: https://github.com/rust-lang-nursery/log/compare/0.4.9...0.4.10 +[0.4.9]: https://github.com/rust-lang-nursery/log/compare/0.4.8...0.4.9 +[0.4.8]: https://github.com/rust-lang-nursery/log/compare/0.4.7...0.4.8 +[0.4.7]: https://github.com/rust-lang-nursery/log/compare/0.4.6...0.4.7 +[0.4.6]: https://github.com/rust-lang-nursery/log/compare/0.4.5...0.4.6 +[0.4.5]: https://github.com/rust-lang-nursery/log/compare/0.4.4...0.4.5 +[0.4.4]: https://github.com/rust-lang-nursery/log/compare/0.4.3...0.4.4 +[0.4.3]: https://github.com/rust-lang-nursery/log/compare/0.4.2...0.4.3 +[0.4.2]: https://github.com/rust-lang-nursery/log/compare/0.4.1...0.4.2 +[0.4.1]: https://github.com/rust-lang-nursery/log/compare/0.4.0...0.4.1 +[0.4.0]: https://github.com/rust-lang-nursery/log/compare/0.3.8...0.4.0 +[release tags]: https://github.com/rust-lang-nursery/log/releases diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/Cargo.toml b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/Cargo.toml new file mode 100644 index 0000000..a199e31 --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/Cargo.toml @@ -0,0 +1,139 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2018" +rust-version = "1.60.0" +name = "log" +version = "0.4.22" +authors = ["The Rust Project Developers"] +exclude = ["rfcs/**/*"] +description = """ +A lightweight logging facade for Rust +""" +documentation = "https://docs.rs/log" +readme = "README.md" +keywords = ["logging"] +categories = ["development-tools::debugging"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/rust-lang/log" + +[package.metadata.docs.rs] +features = [ + "std", + "serde", + "kv_std", + "kv_sval", + "kv_serde", +] + +[[test]] +name = "integration" +path = "tests/integration.rs" +harness = false + +[[test]] +name = "macros" +path = "tests/macros.rs" +harness = true + +[dependencies.serde] +version = "1.0" +optional = true +default-features = false + +[dependencies.sval] +version = "2.1" +optional = true +default-features = false + +[dependencies.sval_ref] +version = "2.1" +optional = true +default-features = false + +[dependencies.value-bag] +version = "1.7" +features = ["inline-i128"] +optional = true +default-features = false + +[dev-dependencies.proc-macro2] +version = "1.0.63" +default-features = false + +[dev-dependencies.serde] +version = "1.0" +features = ["derive"] + +[dev-dependencies.serde_json] +version = "1.0" + +[dev-dependencies.serde_test] +version = "1.0" + +[dev-dependencies.sval] +version = "2.1" + +[dev-dependencies.sval_derive] +version = "2.1" + +[dev-dependencies.value-bag] +version = "1.7" +features = ["test"] + +[features] +kv = [] +kv_serde = [ + "kv_std", + "value-bag/serde", + "serde", +] +kv_std = [ + "std", + "kv", + "value-bag/error", +] +kv_sval = [ + "kv", + "value-bag/sval", + "sval", + "sval_ref", +] +kv_unstable = [ + "kv", + "value-bag", +] +kv_unstable_serde = [ + "kv_serde", + "kv_unstable_std", +] +kv_unstable_std = [ + "kv_std", + "kv_unstable", +] +kv_unstable_sval = [ + "kv_sval", + "kv_unstable", +] +max_level_debug = [] +max_level_error = [] +max_level_info = [] +max_level_off = [] +max_level_trace = [] +max_level_warn = [] +release_max_level_debug = [] +release_max_level_error = [] +release_max_level_info = [] +release_max_level_off = [] +release_max_level_trace = [] +release_max_level_warn = [] +std = [] diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/LICENSE-APACHE b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/LICENSE-APACHE new file mode 100644 index 0000000..16fe87b --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/LICENSE-MIT b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/LICENSE-MIT new file mode 100644 index 0000000..39d4bdb --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/README.md b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/README.md new file mode 100644 index 0000000..d4a08b1 --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/README.md @@ -0,0 +1,130 @@ +log +=== + +A Rust library providing a lightweight logging *facade*. + +[](https://github.com/rust-lang/log/actions) +[](https://crates.io/crates/log) +[](https://docs.rs/log) + + +* [`log` documentation](https://docs.rs/log) + +A logging facade provides a single logging API that abstracts over the actual +logging implementation. Libraries can use the logging API provided by this +crate, and the consumer of those libraries can choose the logging +implementation that is most suitable for its use case. + + +## Minimum supported `rustc` + +`1.60.0+` + +This version is explicitly tested in CI and may be bumped in any release as needed. Maintaining compatibility with older compilers is a priority though, so the bar for bumping the minimum supported version is set very high. Any changes to the supported minimum version will be called out in the release notes. + +## Usage + +### In libraries + +Libraries should link only to the `log` crate, and use the provided macros to +log whatever information will be useful to downstream consumers: + +```toml +[dependencies] +log = "0.4" +``` + +```rust +use log::{info, trace, warn}; + +pub fn shave_the_yak(yak: &mut Yak) { + trace!("Commencing yak shaving"); + + loop { + match find_a_razor() { + Ok(razor) => { + info!("Razor located: {razor}"); + yak.shave(razor); + break; + } + Err(err) => { + warn!("Unable to locate a razor: {err}, retrying"); + } + } + } +} +``` + +### In executables + +In order to produce log output, executables have to use a logger implementation compatible with the facade. +There are many available implementations to choose from, here are some options: + +* Simple minimal loggers: + * [`env_logger`](https://docs.rs/env_logger/*/env_logger/) + * [`colog`](https://docs.rs/colog/*/colog/) + * [`simple_logger`](https://docs.rs/simple_logger/*/simple_logger/) + * [`simplelog`](https://docs.rs/simplelog/*/simplelog/) + * [`pretty_env_logger`](https://docs.rs/pretty_env_logger/*/pretty_env_logger/) + * [`stderrlog`](https://docs.rs/stderrlog/*/stderrlog/) + * [`flexi_logger`](https://docs.rs/flexi_logger/*/flexi_logger/) + * [`call_logger`](https://docs.rs/call_logger/*/call_logger/) + * [`std-logger`](https://docs.rs/std-logger/*/std_logger/) + * [`structured-logger`](https://docs.rs/structured-logger/latest/structured_logger/) +* Complex configurable frameworks: + * [`log4rs`](https://docs.rs/log4rs/*/log4rs/) + * [`fern`](https://docs.rs/fern/*/fern/) +* Adaptors for other facilities: + * [`syslog`](https://docs.rs/syslog/*/syslog/) + * [`systemd-journal-logger`](https://docs.rs/systemd-journal-logger/*/systemd_journal_logger/) + * [`slog-stdlog`](https://docs.rs/slog-stdlog/*/slog_stdlog/) + * [`android_log`](https://docs.rs/android_log/*/android_log/) + * [`win_dbg_logger`](https://docs.rs/win_dbg_logger/*/win_dbg_logger/) + * [`db_logger`](https://docs.rs/db_logger/*/db_logger/) + * [`log-to-defmt`](https://docs.rs/log-to-defmt/*/log_to_defmt/) + * [`logcontrol-log`](https://docs.rs/logcontrol-log/*/logcontrol_log/) +* For WebAssembly binaries: + * [`console_log`](https://docs.rs/console_log/*/console_log/) +* For dynamic libraries: + * You may need to construct [an FFI-safe wrapper over `log`](https://github.com/rust-lang/log/issues/421) to initialize in your libraries. +* Utilities: + * [`log_err`](https://docs.rs/log_err/*/log_err/) + * [`log-reload`](https://docs.rs/log-reload/*/log_reload/) + * [`alterable_logger`](https://docs.rs/alterable_logger/*/alterable_logger) + +Executables should choose a logger implementation and initialize it early in the +runtime of the program. Logger implementations will typically include a +function to do this. Any log messages generated before the logger is +initialized will be ignored. + +The executable itself may use the `log` crate to log as well. + +## Structured logging + +If you enable the `kv` feature, you can associate structured data with your log records: + +```rust +use log::{info, trace, warn}; + +pub fn shave_the_yak(yak: &mut Yak) { + // `yak:serde` will capture `yak` using its `serde::Serialize` impl + // + // You could also use `:?` for `Debug`, or `:%` for `Display`. For a + // full list, see the `log` crate documentation + trace!(target = "yak_events", yak:serde; "Commencing yak shaving"); + + loop { + match find_a_razor() { + Ok(razor) => { + info!(razor; "Razor located"); + yak.shave(razor); + break; + } + Err(e) => { + // `e:err` will capture `e` using its `std::error::Error` impl + warn!(e:err; "Unable to locate a razor, retrying"); + } + } + } +} +``` diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/benches/value.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/benches/value.rs new file mode 100644 index 0000000..3d0f18b --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/benches/value.rs @@ -0,0 +1,27 @@ +#![cfg(feature = "kv")] +#![feature(test)] + +use log::kv::Value; + +#[bench] +fn u8_to_value(b: &mut test::Bencher) { + b.iter(|| Value::from(1u8)); +} + +#[bench] +fn u8_to_value_debug(b: &mut test::Bencher) { + b.iter(|| Value::from_debug(&1u8)); +} + +#[bench] +fn str_to_value_debug(b: &mut test::Bencher) { + b.iter(|| Value::from_debug(&"a string")); +} + +#[bench] +fn custom_to_value_debug(b: &mut test::Bencher) { + #[derive(Debug)] + struct A; + + b.iter(|| Value::from_debug(&A)); +} diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/__private_api.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/__private_api.rs new file mode 100644 index 0000000..11bc2fc --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/__private_api.rs @@ -0,0 +1,123 @@ +//! WARNING: this is not part of the crate's public API and is subject to change at any time + +use self::sealed::KVs; +use crate::{Level, Metadata, Record}; +use std::fmt::Arguments; +use std::panic::Location; +pub use std::{format_args, module_path, stringify}; + +#[cfg(not(feature = "kv"))] +pub type Value<'a> = &'a str; + +mod sealed { + /// Types for the `kv` argument. + pub trait KVs<'a> { + fn into_kvs(self) -> Option<&'a [(&'a str, super::Value<'a>)]>; + } +} + +// Types for the `kv` argument. + +impl<'a> KVs<'a> for &'a [(&'a str, Value<'a>)] { + #[inline] + fn into_kvs(self) -> Option<&'a [(&'a str, Value<'a>)]> { + Some(self) + } +} + +impl<'a> KVs<'a> for () { + #[inline] + fn into_kvs(self) -> Option<&'a [(&'a str, Value<'a>)]> { + None + } +} + +// Log implementation. + +fn log_impl( + args: Arguments, + level: Level, + &(target, module_path, loc): &(&str, &'static str, &'static Location), + kvs: Option<&[(&str, Value)]>, +) { + #[cfg(not(feature = "kv"))] + if kvs.is_some() { + panic!("key-value support is experimental and must be enabled using the `kv` feature") + } + + let mut builder = Record::builder(); + + builder + .args(args) + .level(level) + .target(target) + .module_path_static(Some(module_path)) + .file_static(Some(loc.file())) + .line(Some(loc.line())); + + #[cfg(feature = "kv")] + builder.key_values(&kvs); + + crate::logger().log(&builder.build()); +} + +pub fn log<'a, K>( + args: Arguments, + level: Level, + target_module_path_and_loc: &(&str, &'static str, &'static Location), + kvs: K, +) where + K: KVs<'a>, +{ + log_impl(args, level, target_module_path_and_loc, kvs.into_kvs()) +} + +pub fn enabled(level: Level, target: &str) -> bool { + crate::logger().enabled(&Metadata::builder().level(level).target(target).build()) +} + +#[track_caller] +pub fn loc() -> &'static Location<'static> { + Location::caller() +} + +#[cfg(feature = "kv")] +mod kv_support { + use crate::kv; + + pub type Value<'a> = kv::Value<'a>; + + // NOTE: Many functions here accept a double reference &&V + // This is so V itself can be ?Sized, while still letting us + // erase it to some dyn Trait (because &T is sized) + + pub fn capture_to_value<'a, V: kv::ToValue + ?Sized>(v: &'a &'a V) -> Value<'a> { + v.to_value() + } + + pub fn capture_debug<'a, V: core::fmt::Debug + ?Sized>(v: &'a &'a V) -> Value<'a> { + Value::from_debug(v) + } + + pub fn capture_display<'a, V: core::fmt::Display + ?Sized>(v: &'a &'a V) -> Value<'a> { + Value::from_display(v) + } + + #[cfg(feature = "kv_std")] + pub fn capture_error<'a>(v: &'a (dyn std::error::Error + 'static)) -> Value<'a> { + Value::from_dyn_error(v) + } + + #[cfg(feature = "kv_sval")] + pub fn capture_sval<'a, V: sval::Value + ?Sized>(v: &'a &'a V) -> Value<'a> { + Value::from_sval(v) + } + + #[cfg(feature = "kv_serde")] + pub fn capture_serde<'a, V: serde::Serialize + ?Sized>(v: &'a &'a V) -> Value<'a> { + Value::from_serde(v) + } +} + +#[cfg(feature = "kv")] +pub use self::kv_support::*; diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/kv/error.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/kv/error.rs new file mode 100644 index 0000000..7efa5af --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/kv/error.rs @@ -0,0 +1,94 @@ +use std::fmt; + +/// An error encountered while working with structured data. +#[derive(Debug)] +pub struct Error { + inner: Inner, +} + +#[derive(Debug)] +enum Inner { + #[cfg(feature = "std")] + Boxed(std_support::BoxedError), + Msg(&'static str), + #[cfg(feature = "value-bag")] + Value(crate::kv::value::inner::Error), + Fmt, +} + +impl Error { + /// Create an error from a message. + pub fn msg(msg: &'static str) -> Self { + Error { + inner: Inner::Msg(msg), + } + } + + // Not public so we don't leak the `crate::kv::value::inner` API + #[cfg(feature = "value-bag")] + pub(super) fn from_value(err: crate::kv::value::inner::Error) -> Self { + Error { + inner: Inner::Value(err), + } + } + + // Not public so we don't leak the `crate::kv::value::inner` API + #[cfg(feature = "value-bag")] + pub(super) fn into_value(self) -> crate::kv::value::inner::Error { + match self.inner { + Inner::Value(err) => err, + #[cfg(feature = "kv_std")] + _ => crate::kv::value::inner::Error::boxed(self), + #[cfg(not(feature = "kv_std"))] + _ => crate::kv::value::inner::Error::msg("error inspecting a value"), + } + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use self::Inner::*; + match &self.inner { + #[cfg(feature = "std")] + Boxed(err) => err.fmt(f), + #[cfg(feature = "value-bag")] + Value(err) => err.fmt(f), + Msg(msg) => msg.fmt(f), + Fmt => fmt::Error.fmt(f), + } + } +} + +impl From<fmt::Error> for Error { + fn from(_: fmt::Error) -> Self { + Error { inner: Inner::Fmt } + } +} + +#[cfg(feature = "std")] +mod std_support { + use super::*; + use std::{error, io}; + + pub(super) type BoxedError = Box<dyn error::Error + Send + Sync>; + + impl Error { + /// Create an error from a standard error type. + pub fn boxed<E>(err: E) -> Self + where + E: Into<BoxedError>, + { + Error { + inner: Inner::Boxed(err.into()), + } + } + } + + impl error::Error for Error {} + + impl From<io::Error> for Error { + fn from(err: io::Error) -> Self { + Error::boxed(err) + } + } +} diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/kv/key.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/kv/key.rs new file mode 100644 index 0000000..9a64b95 --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/kv/key.rs @@ -0,0 +1,143 @@ +//! Structured keys. + +use std::borrow::Borrow; +use std::fmt; + +/// A type that can be converted into a [`Key`](struct.Key.html). +pub trait ToKey { + /// Perform the conversion. + fn to_key(&self) -> Key; +} + +impl<'a, T> ToKey for &'a T +where + T: ToKey + ?Sized, +{ + fn to_key(&self) -> Key { + (**self).to_key() + } +} + +impl<'k> ToKey for Key<'k> { + fn to_key(&self) -> Key { + Key { key: self.key } + } +} + +impl ToKey for str { + fn to_key(&self) -> Key { + Key::from_str(self) + } +} + +/// A key in a key-value. +// These impls must only be based on the as_str() representation of the key +// If a new field (such as an optional index) is added to the key they must not affect comparison +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Key<'k> { + key: &'k str, +} + +impl<'k> Key<'k> { + /// Get a key from a borrowed string. + pub fn from_str(key: &'k str) -> Self { + Key { key } + } + + /// Get a borrowed string from this key. + pub fn as_str(&self) -> &str { + self.key + } +} + +impl<'k> fmt::Display for Key<'k> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.key.fmt(f) + } +} + +impl<'k> AsRef<str> for Key<'k> { + fn as_ref(&self) -> &str { + self.as_str() + } +} + +impl<'k> Borrow<str> for Key<'k> { + fn borrow(&self) -> &str { + self.as_str() + } +} + +impl<'k> From<&'k str> for Key<'k> { + fn from(s: &'k str) -> Self { + Key::from_str(s) + } +} + +#[cfg(feature = "std")] +mod std_support { + use super::*; + + use std::borrow::Cow; + + impl ToKey for String { + fn to_key(&self) -> Key { + Key::from_str(self) + } + } + + impl<'a> ToKey for Cow<'a, str> { + fn to_key(&self) -> Key { + Key::from_str(self) + } + } +} + +#[cfg(feature = "kv_sval")] +mod sval_support { + use super::*; + + use sval::Value; + use sval_ref::ValueRef; + + impl<'a> Value for Key<'a> { + fn stream<'sval, S: sval::Stream<'sval> + ?Sized>( + &'sval self, + stream: &mut S, + ) -> sval::Result { + self.key.stream(stream) + } + } + + impl<'a> ValueRef<'a> for Key<'a> { + fn stream_ref<S: sval::Stream<'a> + ?Sized>(&self, stream: &mut S) -> sval::Result { + self.key.stream(stream) + } + } +} + +#[cfg(feature = "kv_serde")] +mod serde_support { + use super::*; + + use serde::{Serialize, Serializer}; + + impl<'a> Serialize for Key<'a> { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + self.key.serialize(serializer) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn key_from_string() { + assert_eq!("a key", Key::from_str("a key").as_str()); + } +} diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/kv/mod.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/kv/mod.rs new file mode 100644 index 0000000..1ccb825 --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/kv/mod.rs @@ -0,0 +1,265 @@ +//! Structured logging. +//! +//! Add the `kv` feature to your `Cargo.toml` to enable +//! this module: +//! +//! ```toml +//! [dependencies.log] +//! features = ["kv"] +//! ``` +//! +//! # Structured logging in `log` +//! +//! Structured logging enhances traditional text-based log records with user-defined +//! attributes. Structured logs can be analyzed using a variety of data processing +//! techniques, without needing to find and parse attributes from unstructured text first. +//! +//! In `log`, user-defined attributes are part of a [`Source`] on the log record. +//! Each attribute is a key-value; a pair of [`Key`] and [`Value`]. Keys are strings +//! and values are a datum of any type that can be formatted or serialized. Simple types +//! like strings, booleans, and numbers are supported, as well as arbitrarily complex +//! structures involving nested objects and sequences. +//! +//! ## Adding key-values to log records +//! +//! Key-values appear before the message format in the `log!` macros: +//! +//! ``` +//! # use log::info; +//! info!(a = 1; "Something of interest"); +//! ``` +//! +//! Key-values support the same shorthand identifer syntax as `format_args`: +//! +//! ``` +//! # use log::info; +//! let a = 1; +//! +//! info!(a; "Something of interest"); +//! ``` +//! +//! Values are capturing using the [`ToValue`] trait by default. To capture a value +//! using a different trait implementation, use a modifier after its key. Here's how +//! the same example can capture `a` using its `Debug` implementation instead: +//! +//! ``` +//! # use log::info; +//! info!(a:? = 1; "Something of interest"); +//! ``` +//! +//! The following capturing modifiers are supported: +//! +//! - `:?` will capture the value using `Debug`. +//! - `:debug` will capture the value using `Debug`. +//! - `:%` will capture the value using `Display`. +//! - `:display` will capture the value using `Display`. +//! - `:err` will capture the value using `std::error::Error` (requires the `kv_std` feature). +//! - `:sval` will capture the value using `sval::Value` (requires the `kv_sval` feature). +//! - `:serde` will capture the value using `serde::Serialize` (requires the `kv_serde` feature). +//! +//! ## Working with key-values on log records +//! +//! Use the [`Record::key_values`](../struct.Record.html#method.key_values) method to access key-values. +//! +//! Individual values can be pulled from the source by their key: +//! +//! ``` +//! # fn main() -> Result<(), log::kv::Error> { +//! use log::kv::{Source, Key, Value}; +//! # let record = log::Record::builder().key_values(&[("a", 1)]).build(); +//! +//! // info!(a = 1; "Something of interest"); +//! +//! let a: Value = record.key_values().get(Key::from("a")).unwrap(); +//! assert_eq!(1, a.to_i64().unwrap()); +//! # Ok(()) +//! # } +//! ``` +//! +//! All key-values can also be enumerated using a [`VisitSource`]: +//! +//! ``` +//! # fn main() -> Result<(), log::kv::Error> { +//! use std::collections::BTreeMap; +//! +//! use log::kv::{self, Source, Key, Value, VisitSource}; +//! +//! struct Collect<'kvs>(BTreeMap<Key<'kvs>, Value<'kvs>>); +//! +//! impl<'kvs> VisitSource<'kvs> for Collect<'kvs> { +//! fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), kv::Error> { +//! self.0.insert(key, value); +//! +//! Ok(()) +//! } +//! } +//! +//! let mut visitor = Collect(BTreeMap::new()); +//! +//! # let record = log::Record::builder().key_values(&[("a", 1), ("b", 2), ("c", 3)]).build(); +//! // info!(a = 1, b = 2, c = 3; "Something of interest"); +//! +//! record.key_values().visit(&mut visitor)?; +//! +//! let collected = visitor.0; +//! +//! assert_eq!( +//! vec!["a", "b", "c"], +//! collected +//! .keys() +//! .map(|k| k.as_str()) +//! .collect::<Vec<_>>(), +//! ); +//! # Ok(()) +//! # } +//! ``` +//! +//! [`Value`]s have methods for conversions to common types: +//! +//! ``` +//! # fn main() -> Result<(), log::kv::Error> { +//! use log::kv::{Source, Key}; +//! # let record = log::Record::builder().key_values(&[("a", 1)]).build(); +//! +//! // info!(a = 1; "Something of interest"); +//! +//! let a = record.key_values().get(Key::from("a")).unwrap(); +//! +//! assert_eq!(1, a.to_i64().unwrap()); +//! # Ok(()) +//! # } +//! ``` +//! +//! Values also have their own [`VisitValue`] type. Value visitors are a lightweight +//! API for working with primitives types: +//! +//! ``` +//! # fn main() -> Result<(), log::kv::Error> { +//! use log::kv::{self, Source, Key, VisitValue}; +//! # let record = log::Record::builder().key_values(&[("a", 1)]).build(); +//! +//! struct IsNumeric(bool); +//! +//! impl<'kvs> VisitValue<'kvs> for IsNumeric { +//! fn visit_any(&mut self, _value: kv::Value) -> Result<(), kv::Error> { +//! self.0 = false; +//! Ok(()) +//! } +//! +//! fn visit_u64(&mut self, _value: u64) -> Result<(), kv::Error> { +//! self.0 = true; +//! Ok(()) +//! } +//! +//! fn visit_i64(&mut self, _value: i64) -> Result<(), kv::Error> { +//! self.0 = true; +//! Ok(()) +//! } +//! +//! fn visit_u128(&mut self, _value: u128) -> Result<(), kv::Error> { +//! self.0 = true; +//! Ok(()) +//! } +//! +//! fn visit_i128(&mut self, _value: i128) -> Result<(), kv::Error> { +//! self.0 = true; +//! Ok(()) +//! } +//! +//! fn visit_f64(&mut self, _value: f64) -> Result<(), kv::Error> { +//! self.0 = true; +//! Ok(()) +//! } +//! } +//! +//! // info!(a = 1; "Something of interest"); +//! +//! let a = record.key_values().get(Key::from("a")).unwrap(); +//! +//! let mut visitor = IsNumeric(false); +//! +//! a.visit(&mut visitor)?; +//! +//! let is_numeric = visitor.0; +//! +//! assert!(is_numeric); +//! # Ok(()) +//! # } +//! ``` +//! +//! To serialize a value to a format like JSON, you can also use either `serde` or `sval`: +//! +//! ``` +//! # fn main() -> Result<(), Box<dyn std::error::Error>> { +//! # #[cfg(feature = "serde")] +//! # { +//! # use log::kv::Key; +//! #[derive(serde::Serialize)] +//! struct Data { +//! a: i32, b: bool, +//! c: &'static str, +//! } +//! +//! let data = Data { a: 1, b: true, c: "Some data" }; +//! +//! # let source = [("a", log::kv::Value::from_serde(&data))]; +//! # let record = log::Record::builder().key_values(&source).build(); +//! // info!(a = data; "Something of interest"); +//! +//! let a = record.key_values().get(Key::from("a")).unwrap(); +//! +//! assert_eq!("{\"a\":1,\"b\":true,\"c\":\"Some data\"}", serde_json::to_string(&a)?); +//! # } +//! # Ok(()) +//! # } +//! ``` +//! +//! The choice of serialization framework depends on the needs of the consumer. +//! If you're in a no-std environment, you can use `sval`. In other cases, you can use `serde`. +//! Log producers and log consumers don't need to agree on the serialization framework. +//! A value can be captured using its `serde::Serialize` implementation and still be serialized +//! through `sval` without losing any structure or data. +//! +//! Values can also always be formatted using the standard `Debug` and `Display` +//! traits: +//! +//! ``` +//! # use log::kv::Key; +//! # #[derive(Debug)] +//! struct Data { +//! a: i32, +//! b: bool, +//! c: &'static str, +//! } +//! +//! let data = Data { a: 1, b: true, c: "Some data" }; +//! +//! # let source = [("a", log::kv::Value::from_debug(&data))]; +//! # let record = log::Record::builder().key_values(&source).build(); +//! // info!(a = data; "Something of interest"); +//! +//! let a = record.key_values().get(Key::from("a")).unwrap(); +//! +//! assert_eq!("Data { a: 1, b: true, c: \"Some data\" }", format!("{a:?}")); +//! ``` + +mod error; +mod key; + +#[cfg(not(feature = "kv_unstable"))] +mod source; +#[cfg(not(feature = "kv_unstable"))] +mod value; + +pub use self::error::Error; +pub use self::key::{Key, ToKey}; +pub use self::source::{Source, VisitSource}; +pub use self::value::{ToValue, Value, VisitValue}; + +#[cfg(feature = "kv_unstable")] +pub mod source; +#[cfg(feature = "kv_unstable")] +pub mod value; + +#[cfg(feature = "kv_unstable")] +pub use self::source::Visitor; diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/kv/source.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/kv/source.rs new file mode 100644 index 0000000..f463e6d --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/kv/source.rs @@ -0,0 +1,514 @@ +//! Sources for key-values. +//! +//! This module defines the [`Source`] type and supporting APIs for +//! working with collections of key-values. + +use crate::kv::{Error, Key, ToKey, ToValue, Value}; +use std::fmt; + +/// A source of key-values. +/// +/// The source may be a single pair, a set of pairs, or a filter over a set of pairs. +/// Use the [`VisitSource`](trait.VisitSource.html) trait to inspect the structured data +/// in a source. +/// +/// A source is like an iterator over its key-values, except with a push-based API +/// instead of a pull-based one. +/// +/// # Examples +/// +/// Enumerating the key-values in a source: +/// +/// ``` +/// # fn main() -> Result<(), log::kv::Error> { +/// use log::kv::{self, Source, Key, Value, VisitSource}; +/// +/// // A `VisitSource` that prints all key-values +/// // VisitSources are fed the key-value pairs of each key-values +/// struct Printer; +/// +/// impl<'kvs> VisitSource<'kvs> for Printer { +/// fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), kv::Error> { +/// println!("{key}: {value}"); +/// +/// Ok(()) +/// } +/// } +/// +/// // A source with 3 key-values +/// // Common collection types implement the `Source` trait +/// let source = &[ +/// ("a", 1), +/// ("b", 2), +/// ("c", 3), +/// ]; +/// +/// // Pass an instance of the `VisitSource` to a `Source` to visit it +/// source.visit(&mut Printer)?; +/// # Ok(()) +/// # } +/// ``` +pub trait Source { + /// Visit key-values. + /// + /// A source doesn't have to guarantee any ordering or uniqueness of key-values. + /// If the given visitor returns an error then the source may early-return with it, + /// even if there are more key-values. + /// + /// # Implementation notes + /// + /// A source should yield the same key-values to a subsequent visitor unless + /// that visitor itself fails. + fn visit<'kvs>(&'kvs self, visitor: &mut dyn VisitSource<'kvs>) -> Result<(), Error>; + + /// Get the value for a given key. + /// + /// If the key appears multiple times in the source then which key is returned + /// is implementation specific. + /// + /// # Implementation notes + /// + /// A source that can provide a more efficient implementation of this method + /// should override it. + fn get(&self, key: Key) -> Option<Value<'_>> { + get_default(self, key) + } + + /// Count the number of key-values that can be visited. + /// + /// # Implementation notes + /// + /// A source that knows the number of key-values upfront may provide a more + /// efficient implementation. + /// + /// A subsequent call to `visit` should yield the same number of key-values. + fn count(&self) -> usize { + count_default(self) + } +} + +/// The default implementation of `Source::get` +fn get_default<'v>(source: &'v (impl Source + ?Sized), key: Key) -> Option<Value<'v>> { + struct Get<'k, 'v> { + key: Key<'k>, + found: Option<Value<'v>>, + } + + impl<'k, 'kvs> VisitSource<'kvs> for Get<'k, 'kvs> { + fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), Error> { + if self.key == key { + self.found = Some(value); + } + + Ok(()) + } + } + + let mut get = Get { key, found: None }; + + let _ = source.visit(&mut get); + get.found +} + +/// The default implementation of `Source::count`. +fn count_default(source: impl Source) -> usize { + struct Count(usize); + + impl<'kvs> VisitSource<'kvs> for Count { + fn visit_pair(&mut self, _: Key<'kvs>, _: Value<'kvs>) -> Result<(), Error> { + self.0 += 1; + + Ok(()) + } + } + + let mut count = Count(0); + let _ = source.visit(&mut count); + count.0 +} + +impl<'a, T> Source for &'a T +where + T: Source + ?Sized, +{ + fn visit<'kvs>(&'kvs self, visitor: &mut dyn VisitSource<'kvs>) -> Result<(), Error> { + Source::visit(&**self, visitor) + } + + fn get(&self, key: Key) -> Option<Value<'_>> { + Source::get(&**self, key) + } + + fn count(&self) -> usize { + Source::count(&**self) + } +} + +impl<K, V> Source for (K, V) +where + K: ToKey, + V: ToValue, +{ + fn visit<'kvs>(&'kvs self, visitor: &mut dyn VisitSource<'kvs>) -> Result<(), Error> { + visitor.visit_pair(self.0.to_key(), self.1.to_value()) + } + + fn get(&self, key: Key) -> Option<Value<'_>> { + if self.0.to_key() == key { + Some(self.1.to_value()) + } else { + None + } + } + + fn count(&self) -> usize { + 1 + } +} + +impl<S> Source for [S] +where + S: Source, +{ + fn visit<'kvs>(&'kvs self, visitor: &mut dyn VisitSource<'kvs>) -> Result<(), Error> { + for source in self { + source.visit(visitor)?; + } + + Ok(()) + } + + fn get(&self, key: Key) -> Option<Value<'_>> { + for source in self { + if let Some(found) = source.get(key.clone()) { + return Some(found); + } + } + + None + } + + fn count(&self) -> usize { + self.iter().map(Source::count).sum() + } +} + +impl<const N: usize, S> Source for [S; N] +where + S: Source, +{ + fn visit<'kvs>(&'kvs self, visitor: &mut dyn VisitSource<'kvs>) -> Result<(), Error> { + Source::visit(self as &[_], visitor) + } + + fn get(&self, key: Key) -> Option<Value<'_>> { + Source::get(self as &[_], key) + } + + fn count(&self) -> usize { + Source::count(self as &[_]) + } +} + +impl<S> Source for Option<S> +where + S: Source, +{ + fn visit<'kvs>(&'kvs self, visitor: &mut dyn VisitSource<'kvs>) -> Result<(), Error> { + if let Some(source) = self { + source.visit(visitor)?; + } + + Ok(()) + } + + fn get(&self, key: Key) -> Option<Value<'_>> { + self.as_ref().and_then(|s| s.get(key)) + } + + fn count(&self) -> usize { + self.as_ref().map_or(0, Source::count) + } +} + +/// A visitor for the key-value pairs in a [`Source`](trait.Source.html). +pub trait VisitSource<'kvs> { + /// Visit a key-value pair. + fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), Error>; +} + +impl<'a, 'kvs, T> VisitSource<'kvs> for &'a mut T +where + T: VisitSource<'kvs> + ?Sized, +{ + fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), Error> { + (**self).visit_pair(key, value) + } +} + +impl<'a, 'b: 'a, 'kvs> VisitSource<'kvs> for fmt::DebugMap<'a, 'b> { + fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), Error> { + self.entry(&key, &value); + Ok(()) + } +} + +impl<'a, 'b: 'a, 'kvs> VisitSource<'kvs> for fmt::DebugList<'a, 'b> { + fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), Error> { + self.entry(&(key, value)); + Ok(()) + } +} + +impl<'a, 'b: 'a, 'kvs> VisitSource<'kvs> for fmt::DebugSet<'a, 'b> { + fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), Error> { + self.entry(&(key, value)); + Ok(()) + } +} + +impl<'a, 'b: 'a, 'kvs> VisitSource<'kvs> for fmt::DebugTuple<'a, 'b> { + fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), Error> { + self.field(&key); + self.field(&value); + Ok(()) + } +} + +#[cfg(feature = "std")] +mod std_support { + use super::*; + use std::borrow::Borrow; + use std::collections::{BTreeMap, HashMap}; + use std::hash::{BuildHasher, Hash}; + use std::rc::Rc; + use std::sync::Arc; + + impl<S> Source for Box<S> + where + S: Source + ?Sized, + { + fn visit<'kvs>(&'kvs self, visitor: &mut dyn VisitSource<'kvs>) -> Result<(), Error> { + Source::visit(&**self, visitor) + } + + fn get(&self, key: Key) -> Option<Value<'_>> { + Source::get(&**self, key) + } + + fn count(&self) -> usize { + Source::count(&**self) + } + } + + impl<S> Source for Arc<S> + where + S: Source + ?Sized, + { + fn visit<'kvs>(&'kvs self, visitor: &mut dyn VisitSource<'kvs>) -> Result<(), Error> { + Source::visit(&**self, visitor) + } + + fn get(&self, key: Key) -> Option<Value<'_>> { + Source::get(&**self, key) + } + + fn count(&self) -> usize { + Source::count(&**self) + } + } + + impl<S> Source for Rc<S> + where + S: Source + ?Sized, + { + fn visit<'kvs>(&'kvs self, visitor: &mut dyn VisitSource<'kvs>) -> Result<(), Error> { + Source::visit(&**self, visitor) + } + + fn get(&self, key: Key) -> Option<Value<'_>> { + Source::get(&**self, key) + } + + fn count(&self) -> usize { + Source::count(&**self) + } + } + + impl<S> Source for Vec<S> + where + S: Source, + { + fn visit<'kvs>(&'kvs self, visitor: &mut dyn VisitSource<'kvs>) -> Result<(), Error> { + Source::visit(&**self, visitor) + } + + fn get(&self, key: Key) -> Option<Value<'_>> { + Source::get(&**self, key) + } + + fn count(&self) -> usize { + Source::count(&**self) + } + } + + impl<'kvs, V> VisitSource<'kvs> for Box<V> + where + V: VisitSource<'kvs> + ?Sized, + { + fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), Error> { + (**self).visit_pair(key, value) + } + } + + impl<K, V, S> Source for HashMap<K, V, S> + where + K: ToKey + Borrow<str> + Eq + Hash, + V: ToValue, + S: BuildHasher, + { + fn visit<'kvs>(&'kvs self, visitor: &mut dyn VisitSource<'kvs>) -> Result<(), Error> { + for (key, value) in self { + visitor.visit_pair(key.to_key(), value.to_value())?; + } + Ok(()) + } + + fn get(&self, key: Key) -> Option<Value<'_>> { + HashMap::get(self, key.as_str()).map(|v| v.to_value()) + } + + fn count(&self) -> usize { + self.len() + } + } + + impl<K, V> Source for BTreeMap<K, V> + where + K: ToKey + Borrow<str> + Ord, + V: ToValue, + { + fn visit<'kvs>(&'kvs self, visitor: &mut dyn VisitSource<'kvs>) -> Result<(), Error> { + for (key, value) in self { + visitor.visit_pair(key.to_key(), value.to_value())?; + } + Ok(()) + } + + fn get(&self, key: Key) -> Option<Value<'_>> { + BTreeMap::get(self, key.as_str()).map(|v| v.to_value()) + } + + fn count(&self) -> usize { + self.len() + } + } + + #[cfg(test)] + mod tests { + use crate::kv::value; + + use super::*; + + #[test] + fn count() { + assert_eq!(1, Source::count(&Box::new(("a", 1)))); + assert_eq!(2, Source::count(&vec![("a", 1), ("b", 2)])); + } + + #[test] + fn get() { + let source = vec![("a", 1), ("b", 2), ("a", 1)]; + assert_eq!( + value::inner::Token::I64(1), + Source::get(&source, Key::from_str("a")).unwrap().to_token() + ); + + let source = Box::new(None::<(&str, i32)>); + assert!(Source::get(&source, Key::from_str("a")).is_none()); + } + + #[test] + fn hash_map() { + let mut map = HashMap::new(); + map.insert("a", 1); + map.insert("b", 2); + + assert_eq!(2, Source::count(&map)); + assert_eq!( + value::inner::Token::I64(1), + Source::get(&map, Key::from_str("a")).unwrap().to_token() + ); + } + + #[test] + fn btree_map() { + let mut map = BTreeMap::new(); + map.insert("a", 1); + map.insert("b", 2); + + assert_eq!(2, Source::count(&map)); + assert_eq!( + value::inner::Token::I64(1), + Source::get(&map, Key::from_str("a")).unwrap().to_token() + ); + } + } +} + +// NOTE: Deprecated; but aliases can't carry this attribute +#[cfg(feature = "kv_unstable")] +pub use VisitSource as Visitor; + +#[cfg(test)] +mod tests { + use crate::kv::value; + + use super::*; + + #[test] + fn source_is_object_safe() { + fn _check(_: &dyn Source) {} + } + + #[test] + fn visitor_is_object_safe() { + fn _check(_: &dyn VisitSource) {} + } + + #[test] + fn count() { + struct OnePair { + key: &'static str, + value: i32, + } + + impl Source for OnePair { + fn visit<'kvs>(&'kvs self, visitor: &mut dyn VisitSource<'kvs>) -> Result<(), Error> { + visitor.visit_pair(self.key.to_key(), self.value.to_value()) + } + } + + assert_eq!(1, Source::count(&("a", 1))); + assert_eq!(2, Source::count(&[("a", 1), ("b", 2)] as &[_])); + assert_eq!(0, Source::count(&None::<(&str, i32)>)); + assert_eq!(1, Source::count(&OnePair { key: "a", value: 1 })); + } + + #[test] + fn get() { + let source = &[("a", 1), ("b", 2), ("a", 1)] as &[_]; + assert_eq!( + value::inner::Token::I64(1), + Source::get(source, Key::from_str("a")).unwrap().to_token() + ); + assert_eq!( + value::inner::Token::I64(2), + Source::get(source, Key::from_str("b")).unwrap().to_token() + ); + assert!(Source::get(&source, Key::from_str("c")).is_none()); + + let source = None::<(&str, i32)>; + assert!(Source::get(&source, Key::from_str("a")).is_none()); + } +} diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/kv/value.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/kv/value.rs new file mode 100644 index 0000000..1511dd0 --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/kv/value.rs @@ -0,0 +1,1394 @@ +//! Structured values. +//! +//! This module defines the [`Value`] type and supporting APIs for +//! capturing and serializing them. + +use std::fmt; + +pub use crate::kv::Error; + +/// A type that can be converted into a [`Value`](struct.Value.html). +pub trait ToValue { + /// Perform the conversion. + fn to_value(&self) -> Value; +} + +impl<'a, T> ToValue for &'a T +where + T: ToValue + ?Sized, +{ + fn to_value(&self) -> Value { + (**self).to_value() + } +} + +impl<'v> ToValue for Value<'v> { + fn to_value(&self) -> Value { + Value { + inner: self.inner.clone(), + } + } +} + +/// A value in a key-value. +/// +/// Values are an anonymous bag containing some structured datum. +/// +/// # Capturing values +/// +/// There are a few ways to capture a value: +/// +/// - Using the `Value::from_*` methods. +/// - Using the `ToValue` trait. +/// - Using the standard `From` trait. +/// +/// ## Using the `Value::from_*` methods +/// +/// `Value` offers a few constructor methods that capture values of different kinds. +/// +/// ``` +/// use log::kv::Value; +/// +/// let value = Value::from_debug(&42i32); +/// +/// assert_eq!(None, value.to_i64()); +/// ``` +/// +/// ## Using the `ToValue` trait +/// +/// The `ToValue` trait can be used to capture values generically. +/// It's the bound used by `Source`. +/// +/// ``` +/// # use log::kv::ToValue; +/// let value = 42i32.to_value(); +/// +/// assert_eq!(Some(42), value.to_i64()); +/// ``` +/// +/// ## Using the standard `From` trait +/// +/// Standard types that implement `ToValue` also implement `From`. +/// +/// ``` +/// use log::kv::Value; +/// +/// let value = Value::from(42i32); +/// +/// assert_eq!(Some(42), value.to_i64()); +/// ``` +/// +/// # Data model +/// +/// Values can hold one of a number of types: +/// +/// - **Null:** The absence of any other meaningful value. Note that +/// `Some(Value::null())` is not the same as `None`. The former is +/// `null` while the latter is `undefined`. This is important to be +/// able to tell the difference between a key-value that was logged, +/// but its value was empty (`Some(Value::null())`) and a key-value +/// that was never logged at all (`None`). +/// - **Strings:** `str`, `char`. +/// - **Booleans:** `bool`. +/// - **Integers:** `u8`-`u128`, `i8`-`i128`, `NonZero*`. +/// - **Floating point numbers:** `f32`-`f64`. +/// - **Errors:** `dyn (Error + 'static)`. +/// - **`serde`:** Any type in `serde`'s data model. +/// - **`sval`:** Any type in `sval`'s data model. +/// +/// # Serialization +/// +/// Values provide a number of ways to be serialized. +/// +/// For basic types the [`Value::visit`] method can be used to extract the +/// underlying typed value. However this is limited in the amount of types +/// supported (see the [`VisitValue`] trait methods). +/// +/// For more complex types one of the following traits can be used: +/// * `sval::Value`, requires the `kv_sval` feature. +/// * `serde::Serialize`, requires the `kv_serde` feature. +/// +/// You don't need a visitor to serialize values through `serde` or `sval`. +/// +/// A value can always be serialized using any supported framework, regardless +/// of how it was captured. If, for example, a value was captured using its +/// `Display` implementation, it will serialize through `serde` as a string. If it was +/// captured as a struct using `serde`, it will also serialize as a struct +/// through `sval`, or can be formatted using a `Debug`-compatible representation. +pub struct Value<'v> { + inner: inner::Inner<'v>, +} + +impl<'v> Value<'v> { + /// Get a value from a type implementing `ToValue`. + pub fn from_any<T>(value: &'v T) -> Self + where + T: ToValue, + { + value.to_value() + } + + /// Get a value from a type implementing `std::fmt::Debug`. + pub fn from_debug<T>(value: &'v T) -> Self + where + T: fmt::Debug, + { + Value { + inner: inner::Inner::from_debug(value), + } + } + + /// Get a value from a type implementing `std::fmt::Display`. + pub fn from_display<T>(value: &'v T) -> Self + where + T: fmt::Display, + { + Value { + inner: inner::Inner::from_display(value), + } + } + + /// Get a value from a type implementing `serde::Serialize`. + #[cfg(feature = "kv_serde")] + pub fn from_serde<T>(value: &'v T) -> Self + where + T: serde::Serialize, + { + Value { + inner: inner::Inner::from_serde1(value), + } + } + + /// Get a value from a type implementing `sval::Value`. + #[cfg(feature = "kv_sval")] + pub fn from_sval<T>(value: &'v T) -> Self + where + T: sval::Value, + { + Value { + inner: inner::Inner::from_sval2(value), + } + } + + /// Get a value from a dynamic `std::fmt::Debug`. + pub fn from_dyn_debug(value: &'v dyn fmt::Debug) -> Self { + Value { + inner: inner::Inner::from_dyn_debug(value), + } + } + + /// Get a value from a dynamic `std::fmt::Display`. + pub fn from_dyn_display(value: &'v dyn fmt::Display) -> Self { + Value { + inner: inner::Inner::from_dyn_display(value), + } + } + + /// Get a value from a dynamic error. + #[cfg(feature = "kv_std")] + pub fn from_dyn_error(err: &'v (dyn std::error::Error + 'static)) -> Self { + Value { + inner: inner::Inner::from_dyn_error(err), + } + } + + /// Get a `null` value. + pub fn null() -> Self { + Value { + inner: inner::Inner::empty(), + } + } + + /// Get a value from an internal primitive. + fn from_inner<T>(value: T) -> Self + where + T: Into<inner::Inner<'v>>, + { + Value { + inner: value.into(), + } + } + + /// Inspect this value using a simple visitor. + /// + /// When the `kv_serde` or `kv_sval` features are enabled, you can also + /// serialize a value using its `Serialize` or `Value` implementation. + pub fn visit(&self, visitor: impl VisitValue<'v>) -> Result<(), Error> { + inner::visit(&self.inner, visitor) + } +} + +impl<'v> fmt::Debug for Value<'v> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&self.inner, f) + } +} + +impl<'v> fmt::Display for Value<'v> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.inner, f) + } +} + +#[cfg(feature = "kv_serde")] +impl<'v> serde::Serialize for Value<'v> { + fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error> + where + S: serde::Serializer, + { + self.inner.serialize(s) + } +} + +#[cfg(feature = "kv_sval")] +impl<'v> sval::Value for Value<'v> { + fn stream<'sval, S: sval::Stream<'sval> + ?Sized>(&'sval self, stream: &mut S) -> sval::Result { + sval::Value::stream(&self.inner, stream) + } +} + +#[cfg(feature = "kv_sval")] +impl<'v> sval_ref::ValueRef<'v> for Value<'v> { + fn stream_ref<S: sval::Stream<'v> + ?Sized>(&self, stream: &mut S) -> sval::Result { + sval_ref::ValueRef::stream_ref(&self.inner, stream) + } +} + +impl ToValue for str { + fn to_value(&self) -> Value { + Value::from(self) + } +} + +impl<'v> From<&'v str> for Value<'v> { + fn from(value: &'v str) -> Self { + Value::from_inner(value) + } +} + +impl ToValue for () { + fn to_value(&self) -> Value { + Value::from_inner(()) + } +} + +impl<T> ToValue for Option<T> +where + T: ToValue, +{ + fn to_value(&self) -> Value { + match *self { + Some(ref value) => value.to_value(), + None => Value::from_inner(()), + } + } +} + +macro_rules! impl_to_value_primitive { + ($($into_ty:ty,)*) => { + $( + impl ToValue for $into_ty { + fn to_value(&self) -> Value { + Value::from(*self) + } + } + + impl<'v> From<$into_ty> for Value<'v> { + fn from(value: $into_ty) -> Self { + Value::from_inner(value) + } + } + + impl<'v> From<&'v $into_ty> for Value<'v> { + fn from(value: &'v $into_ty) -> Self { + Value::from_inner(*value) + } + } + )* + }; +} + +macro_rules! impl_to_value_nonzero_primitive { + ($($into_ty:ident,)*) => { + $( + impl ToValue for std::num::$into_ty { + fn to_value(&self) -> Value { + Value::from(self.get()) + } + } + + impl<'v> From<std::num::$into_ty> for Value<'v> { + fn from(value: std::num::$into_ty) -> Self { + Value::from(value.get()) + } + } + + impl<'v> From<&'v std::num::$into_ty> for Value<'v> { + fn from(value: &'v std::num::$into_ty) -> Self { + Value::from(value.get()) + } + } + )* + }; +} + +macro_rules! impl_value_to_primitive { + ($(#[doc = $doc:tt] $into_name:ident -> $into_ty:ty,)*) => { + impl<'v> Value<'v> { + $( + #[doc = $doc] + pub fn $into_name(&self) -> Option<$into_ty> { + self.inner.$into_name() + } + )* + } + } +} + +impl_to_value_primitive![ + usize, u8, u16, u32, u64, u128, isize, i8, i16, i32, i64, i128, f32, f64, char, bool, +]; + +#[rustfmt::skip] +impl_to_value_nonzero_primitive![ + NonZeroUsize, NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, + NonZeroIsize, NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128, +]; + +impl_value_to_primitive![ + #[doc = "Try convert this value into a `u64`."] + to_u64 -> u64, + #[doc = "Try convert this value into a `i64`."] + to_i64 -> i64, + #[doc = "Try convert this value into a `u128`."] + to_u128 -> u128, + #[doc = "Try convert this value into a `i128`."] + to_i128 -> i128, + #[doc = "Try convert this value into a `f64`."] + to_f64 -> f64, + #[doc = "Try convert this value into a `char`."] + to_char -> char, + #[doc = "Try convert this value into a `bool`."] + to_bool -> bool, +]; + +impl<'v> Value<'v> { + /// Try convert this value into an error. + #[cfg(feature = "kv_std")] + pub fn to_borrowed_error(&self) -> Option<&(dyn std::error::Error + 'static)> { + self.inner.to_borrowed_error() + } + + /// Try convert this value into a borrowed string. + pub fn to_borrowed_str(&self) -> Option<&str> { + self.inner.to_borrowed_str() + } +} + +#[cfg(feature = "kv_std")] +mod std_support { + use std::borrow::Cow; + use std::rc::Rc; + use std::sync::Arc; + + use super::*; + + impl<T> ToValue for Box<T> + where + T: ToValue + ?Sized, + { + fn to_value(&self) -> Value { + (**self).to_value() + } + } + + impl<T> ToValue for Arc<T> + where + T: ToValue + ?Sized, + { + fn to_value(&self) -> Value { + (**self).to_value() + } + } + + impl<T> ToValue for Rc<T> + where + T: ToValue + ?Sized, + { + fn to_value(&self) -> Value { + (**self).to_value() + } + } + + impl ToValue for String { + fn to_value(&self) -> Value { + Value::from(&**self) + } + } + + impl<'v> ToValue for Cow<'v, str> { + fn to_value(&self) -> Value { + Value::from(&**self) + } + } + + impl<'v> Value<'v> { + /// Try convert this value into a string. + pub fn to_cow_str(&self) -> Option<Cow<'v, str>> { + self.inner.to_str() + } + } + + impl<'v> From<&'v String> for Value<'v> { + fn from(v: &'v String) -> Self { + Value::from(&**v) + } + } +} + +/// A visitor for a [`Value`]. +/// +/// Also see [`Value`'s documentation on seralization]. Value visitors are a simple alternative +/// to a more fully-featured serialization framework like `serde` or `sval`. A value visitor +/// can differentiate primitive types through methods like [`VisitValue::visit_bool`] and +/// [`VisitValue::visit_str`], but more complex types like maps and sequences +/// will fallthrough to [`VisitValue::visit_any`]. +/// +/// If you're trying to serialize a value to a format like JSON, you can use either `serde` +/// or `sval` directly with the value. You don't need a visitor. +/// +/// [`Value`'s documentation on seralization]: Value#serialization +pub trait VisitValue<'v> { + /// Visit a `Value`. + /// + /// This is the only required method on `VisitValue` and acts as a fallback for any + /// more specific methods that aren't overridden. + /// The `Value` may be formatted using its `fmt::Debug` or `fmt::Display` implementation, + /// or serialized using its `sval::Value` or `serde::Serialize` implementation. + fn visit_any(&mut self, value: Value) -> Result<(), Error>; + + /// Visit an empty value. + fn visit_null(&mut self) -> Result<(), Error> { + self.visit_any(Value::null()) + } + + /// Visit an unsigned integer. + fn visit_u64(&mut self, value: u64) -> Result<(), Error> { + self.visit_any(value.into()) + } + + /// Visit a signed integer. + fn visit_i64(&mut self, value: i64) -> Result<(), Error> { + self.visit_any(value.into()) + } + + /// Visit a big unsigned integer. + fn visit_u128(&mut self, value: u128) -> Result<(), Error> { + self.visit_any((value).into()) + } + + /// Visit a big signed integer. + fn visit_i128(&mut self, value: i128) -> Result<(), Error> { + self.visit_any((value).into()) + } + + /// Visit a floating point. + fn visit_f64(&mut self, value: f64) -> Result<(), Error> { + self.visit_any(value.into()) + } + + /// Visit a boolean. + fn visit_bool(&mut self, value: bool) -> Result<(), Error> { + self.visit_any(value.into()) + } + + /// Visit a string. + fn visit_str(&mut self, value: &str) -> Result<(), Error> { + self.visit_any(value.into()) + } + + /// Visit a string. + fn visit_borrowed_str(&mut self, value: &'v str) -> Result<(), Error> { + self.visit_str(value) + } + + /// Visit a Unicode character. + fn visit_char(&mut self, value: char) -> Result<(), Error> { + let mut b = [0; 4]; + self.visit_str(&*value.encode_utf8(&mut b)) + } + + /// Visit an error. + #[cfg(feature = "kv_std")] + fn visit_error(&mut self, err: &(dyn std::error::Error + 'static)) -> Result<(), Error> { + self.visit_any(Value::from_dyn_error(err)) + } + + /// Visit an error. + #[cfg(feature = "kv_std")] + fn visit_borrowed_error( + &mut self, + err: &'v (dyn std::error::Error + 'static), + ) -> Result<(), Error> { + self.visit_any(Value::from_dyn_error(err)) + } +} + +impl<'a, 'v, T: ?Sized> VisitValue<'v> for &'a mut T +where + T: VisitValue<'v>, +{ + fn visit_any(&mut self, value: Value) -> Result<(), Error> { + (**self).visit_any(value) + } + + fn visit_null(&mut self) -> Result<(), Error> { + (**self).visit_null() + } + + fn visit_u64(&mut self, value: u64) -> Result<(), Error> { + (**self).visit_u64(value) + } + + fn visit_i64(&mut self, value: i64) -> Result<(), Error> { + (**self).visit_i64(value) + } + + fn visit_u128(&mut self, value: u128) -> Result<(), Error> { + (**self).visit_u128(value) + } + + fn visit_i128(&mut self, value: i128) -> Result<(), Error> { + (**self).visit_i128(value) + } + + fn visit_f64(&mut self, value: f64) -> Result<(), Error> { + (**self).visit_f64(value) + } + + fn visit_bool(&mut self, value: bool) -> Result<(), Error> { + (**self).visit_bool(value) + } + + fn visit_str(&mut self, value: &str) -> Result<(), Error> { + (**self).visit_str(value) + } + + fn visit_borrowed_str(&mut self, value: &'v str) -> Result<(), Error> { + (**self).visit_borrowed_str(value) + } + + fn visit_char(&mut self, value: char) -> Result<(), Error> { + (**self).visit_char(value) + } + + #[cfg(feature = "kv_std")] + fn visit_error(&mut self, err: &(dyn std::error::Error + 'static)) -> Result<(), Error> { + (**self).visit_error(err) + } + + #[cfg(feature = "kv_std")] + fn visit_borrowed_error( + &mut self, + err: &'v (dyn std::error::Error + 'static), + ) -> Result<(), Error> { + (**self).visit_borrowed_error(err) + } +} + +#[cfg(feature = "value-bag")] +pub(in crate::kv) mod inner { + /** + An implementation of `Value` based on a library called `value_bag`. + + `value_bag` was written specifically for use in `log`'s value, but was split out when it outgrew + the codebase here. It's a general-purpose type-erasure library that handles mapping between + more fully-featured serialization frameworks. + */ + use super::*; + + pub use value_bag::ValueBag as Inner; + + pub use value_bag::Error; + + #[cfg(test)] + pub use value_bag::test::TestToken as Token; + + pub fn visit<'v>( + inner: &Inner<'v>, + visitor: impl VisitValue<'v>, + ) -> Result<(), crate::kv::Error> { + struct InnerVisitValue<V>(V); + + impl<'v, V> value_bag::visit::Visit<'v> for InnerVisitValue<V> + where + V: VisitValue<'v>, + { + fn visit_any(&mut self, value: value_bag::ValueBag) -> Result<(), Error> { + self.0 + .visit_any(Value { inner: value }) + .map_err(crate::kv::Error::into_value) + } + + fn visit_empty(&mut self) -> Result<(), Error> { + self.0.visit_null().map_err(crate::kv::Error::into_value) + } + + fn visit_u64(&mut self, value: u64) -> Result<(), Error> { + self.0 + .visit_u64(value) + .map_err(crate::kv::Error::into_value) + } + + fn visit_i64(&mut self, value: i64) -> Result<(), Error> { + self.0 + .visit_i64(value) + .map_err(crate::kv::Error::into_value) + } + + fn visit_u128(&mut self, value: u128) -> Result<(), Error> { + self.0 + .visit_u128(value) + .map_err(crate::kv::Error::into_value) + } + + fn visit_i128(&mut self, value: i128) -> Result<(), Error> { + self.0 + .visit_i128(value) + .map_err(crate::kv::Error::into_value) + } + + fn visit_f64(&mut self, value: f64) -> Result<(), Error> { + self.0 + .visit_f64(value) + .map_err(crate::kv::Error::into_value) + } + + fn visit_bool(&mut self, value: bool) -> Result<(), Error> { + self.0 + .visit_bool(value) + .map_err(crate::kv::Error::into_value) + } + + fn visit_str(&mut self, value: &str) -> Result<(), Error> { + self.0 + .visit_str(value) + .map_err(crate::kv::Error::into_value) + } + + fn visit_borrowed_str(&mut self, value: &'v str) -> Result<(), Error> { + self.0 + .visit_borrowed_str(value) + .map_err(crate::kv::Error::into_value) + } + + fn visit_char(&mut self, value: char) -> Result<(), Error> { + self.0 + .visit_char(value) + .map_err(crate::kv::Error::into_value) + } + + #[cfg(feature = "kv_std")] + fn visit_error( + &mut self, + err: &(dyn std::error::Error + 'static), + ) -> Result<(), Error> { + self.0 + .visit_error(err) + .map_err(crate::kv::Error::into_value) + } + + #[cfg(feature = "kv_std")] + fn visit_borrowed_error( + &mut self, + err: &'v (dyn std::error::Error + 'static), + ) -> Result<(), Error> { + self.0 + .visit_borrowed_error(err) + .map_err(crate::kv::Error::into_value) + } + } + + inner + .visit(&mut InnerVisitValue(visitor)) + .map_err(crate::kv::Error::from_value) + } +} + +#[cfg(not(feature = "value-bag"))] +pub(in crate::kv) mod inner { + /** + This is a dependency-free implementation of `Value` when there's no serialization frameworks involved. + In these simple cases a more fully featured solution like `value_bag` isn't needed, so we avoid pulling it in. + + There are a few things here that need to remain consistent with the `value_bag`-based implementation: + + 1. Conversions should always produce the same results. If a conversion here returns `Some`, then + the same `value_bag`-based conversion must also. Of particular note here are floats to ints; they're + based on the standard library's `TryInto` conversions, which need to be convert to `i32` or `u32`, + and then to `f64`. + 2. VisitValues should always be called in the same way. If a particular type of value calls `visit_i64`, + then the same `value_bag`-based visitor must also. + */ + use super::*; + + #[derive(Clone)] + pub enum Inner<'v> { + None, + Bool(bool), + Str(&'v str), + Char(char), + I64(i64), + U64(u64), + F64(f64), + I128(i128), + U128(u128), + Debug(&'v dyn fmt::Debug), + Display(&'v dyn fmt::Display), + } + + impl<'v> From<()> for Inner<'v> { + fn from(_: ()) -> Self { + Inner::None + } + } + + impl<'v> From<bool> for Inner<'v> { + fn from(v: bool) -> Self { + Inner::Bool(v) + } + } + + impl<'v> From<char> for Inner<'v> { + fn from(v: char) -> Self { + Inner::Char(v) + } + } + + impl<'v> From<f32> for Inner<'v> { + fn from(v: f32) -> Self { + Inner::F64(v as f64) + } + } + + impl<'v> From<f64> for Inner<'v> { + fn from(v: f64) -> Self { + Inner::F64(v) + } + } + + impl<'v> From<i8> for Inner<'v> { + fn from(v: i8) -> Self { + Inner::I64(v as i64) + } + } + + impl<'v> From<i16> for Inner<'v> { + fn from(v: i16) -> Self { + Inner::I64(v as i64) + } + } + + impl<'v> From<i32> for Inner<'v> { + fn from(v: i32) -> Self { + Inner::I64(v as i64) + } + } + + impl<'v> From<i64> for Inner<'v> { + fn from(v: i64) -> Self { + Inner::I64(v as i64) + } + } + + impl<'v> From<isize> for Inner<'v> { + fn from(v: isize) -> Self { + Inner::I64(v as i64) + } + } + + impl<'v> From<u8> for Inner<'v> { + fn from(v: u8) -> Self { + Inner::U64(v as u64) + } + } + + impl<'v> From<u16> for Inner<'v> { + fn from(v: u16) -> Self { + Inner::U64(v as u64) + } + } + + impl<'v> From<u32> for Inner<'v> { + fn from(v: u32) -> Self { + Inner::U64(v as u64) + } + } + + impl<'v> From<u64> for Inner<'v> { + fn from(v: u64) -> Self { + Inner::U64(v as u64) + } + } + + impl<'v> From<usize> for Inner<'v> { + fn from(v: usize) -> Self { + Inner::U64(v as u64) + } + } + + impl<'v> From<i128> for Inner<'v> { + fn from(v: i128) -> Self { + Inner::I128(v) + } + } + + impl<'v> From<u128> for Inner<'v> { + fn from(v: u128) -> Self { + Inner::U128(v) + } + } + + impl<'v> From<&'v str> for Inner<'v> { + fn from(v: &'v str) -> Self { + Inner::Str(v) + } + } + + impl<'v> fmt::Debug for Inner<'v> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Inner::None => fmt::Debug::fmt(&None::<()>, f), + Inner::Bool(v) => fmt::Debug::fmt(v, f), + Inner::Str(v) => fmt::Debug::fmt(v, f), + Inner::Char(v) => fmt::Debug::fmt(v, f), + Inner::I64(v) => fmt::Debug::fmt(v, f), + Inner::U64(v) => fmt::Debug::fmt(v, f), + Inner::F64(v) => fmt::Debug::fmt(v, f), + Inner::I128(v) => fmt::Debug::fmt(v, f), + Inner::U128(v) => fmt::Debug::fmt(v, f), + Inner::Debug(v) => fmt::Debug::fmt(v, f), + Inner::Display(v) => fmt::Display::fmt(v, f), + } + } + } + + impl<'v> fmt::Display for Inner<'v> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Inner::None => fmt::Debug::fmt(&None::<()>, f), + Inner::Bool(v) => fmt::Display::fmt(v, f), + Inner::Str(v) => fmt::Display::fmt(v, f), + Inner::Char(v) => fmt::Display::fmt(v, f), + Inner::I64(v) => fmt::Display::fmt(v, f), + Inner::U64(v) => fmt::Display::fmt(v, f), + Inner::F64(v) => fmt::Display::fmt(v, f), + Inner::I128(v) => fmt::Display::fmt(v, f), + Inner::U128(v) => fmt::Display::fmt(v, f), + Inner::Debug(v) => fmt::Debug::fmt(v, f), + Inner::Display(v) => fmt::Display::fmt(v, f), + } + } + } + + impl<'v> Inner<'v> { + pub fn from_debug<T: fmt::Debug>(value: &'v T) -> Self { + Inner::Debug(value) + } + + pub fn from_display<T: fmt::Display>(value: &'v T) -> Self { + Inner::Display(value) + } + + pub fn from_dyn_debug(value: &'v dyn fmt::Debug) -> Self { + Inner::Debug(value) + } + + pub fn from_dyn_display(value: &'v dyn fmt::Display) -> Self { + Inner::Display(value) + } + + pub fn empty() -> Self { + Inner::None + } + + pub fn to_bool(&self) -> Option<bool> { + match self { + Inner::Bool(v) => Some(*v), + _ => None, + } + } + + pub fn to_char(&self) -> Option<char> { + match self { + Inner::Char(v) => Some(*v), + _ => None, + } + } + + pub fn to_f64(&self) -> Option<f64> { + match self { + Inner::F64(v) => Some(*v), + Inner::I64(v) => { + let v: i32 = (*v).try_into().ok()?; + v.try_into().ok() + } + Inner::U64(v) => { + let v: u32 = (*v).try_into().ok()?; + v.try_into().ok() + } + Inner::I128(v) => { + let v: i32 = (*v).try_into().ok()?; + v.try_into().ok() + } + Inner::U128(v) => { + let v: u32 = (*v).try_into().ok()?; + v.try_into().ok() + } + _ => None, + } + } + + pub fn to_i64(&self) -> Option<i64> { + match self { + Inner::I64(v) => Some(*v), + Inner::U64(v) => (*v).try_into().ok(), + Inner::I128(v) => (*v).try_into().ok(), + Inner::U128(v) => (*v).try_into().ok(), + _ => None, + } + } + + pub fn to_u64(&self) -> Option<u64> { + match self { + Inner::U64(v) => Some(*v), + Inner::I64(v) => (*v).try_into().ok(), + Inner::I128(v) => (*v).try_into().ok(), + Inner::U128(v) => (*v).try_into().ok(), + _ => None, + } + } + + pub fn to_u128(&self) -> Option<u128> { + match self { + Inner::U128(v) => Some(*v), + Inner::I64(v) => (*v).try_into().ok(), + Inner::U64(v) => (*v).try_into().ok(), + Inner::I128(v) => (*v).try_into().ok(), + _ => None, + } + } + + pub fn to_i128(&self) -> Option<i128> { + match self { + Inner::I128(v) => Some(*v), + Inner::I64(v) => (*v).try_into().ok(), + Inner::U64(v) => (*v).try_into().ok(), + Inner::U128(v) => (*v).try_into().ok(), + _ => None, + } + } + + pub fn to_borrowed_str(&self) -> Option<&'v str> { + match self { + Inner::Str(v) => Some(v), + _ => None, + } + } + + #[cfg(test)] + pub fn to_test_token(&self) -> Token { + match self { + Inner::None => Token::None, + Inner::Bool(v) => Token::Bool(*v), + Inner::Str(v) => Token::Str(*v), + Inner::Char(v) => Token::Char(*v), + Inner::I64(v) => Token::I64(*v), + Inner::U64(v) => Token::U64(*v), + Inner::F64(v) => Token::F64(*v), + Inner::I128(_) => unimplemented!(), + Inner::U128(_) => unimplemented!(), + Inner::Debug(_) => unimplemented!(), + Inner::Display(_) => unimplemented!(), + } + } + } + + #[cfg(test)] + #[derive(Debug, PartialEq)] + pub enum Token<'v> { + None, + Bool(bool), + Char(char), + Str(&'v str), + F64(f64), + I64(i64), + U64(u64), + } + + pub fn visit<'v>( + inner: &Inner<'v>, + mut visitor: impl VisitValue<'v>, + ) -> Result<(), crate::kv::Error> { + match inner { + Inner::None => visitor.visit_null(), + Inner::Bool(v) => visitor.visit_bool(*v), + Inner::Str(v) => visitor.visit_borrowed_str(*v), + Inner::Char(v) => visitor.visit_char(*v), + Inner::I64(v) => visitor.visit_i64(*v), + Inner::U64(v) => visitor.visit_u64(*v), + Inner::F64(v) => visitor.visit_f64(*v), + Inner::I128(v) => visitor.visit_i128(*v), + Inner::U128(v) => visitor.visit_u128(*v), + Inner::Debug(v) => visitor.visit_any(Value::from_dyn_debug(*v)), + Inner::Display(v) => visitor.visit_any(Value::from_dyn_display(*v)), + } + } +} + +impl<'v> Value<'v> { + /// Get a value from a type implementing `std::fmt::Debug`. + #[cfg(feature = "kv_unstable")] + #[deprecated(note = "use `from_debug` instead")] + pub fn capture_debug<T>(value: &'v T) -> Self + where + T: fmt::Debug + 'static, + { + Value::from_debug(value) + } + + /// Get a value from a type implementing `std::fmt::Display`. + #[cfg(feature = "kv_unstable")] + #[deprecated(note = "use `from_display` instead")] + pub fn capture_display<T>(value: &'v T) -> Self + where + T: fmt::Display + 'static, + { + Value::from_display(value) + } + + /// Get a value from an error. + #[cfg(feature = "kv_unstable_std")] + #[deprecated(note = "use `from_dyn_error` instead")] + pub fn capture_error<T>(err: &'v T) -> Self + where + T: std::error::Error + 'static, + { + Value::from_dyn_error(err) + } + + /// Get a value from a type implementing `serde::Serialize`. + #[cfg(feature = "kv_unstable_serde")] + #[deprecated(note = "use `from_serde` instead")] + pub fn capture_serde<T>(value: &'v T) -> Self + where + T: serde::Serialize + 'static, + { + Value::from_serde(value) + } + + /// Get a value from a type implementing `sval::Value`. + #[cfg(feature = "kv_unstable_sval")] + #[deprecated(note = "use `from_sval` instead")] + pub fn capture_sval<T>(value: &'v T) -> Self + where + T: sval::Value + 'static, + { + Value::from_sval(value) + } + + /// Check whether this value can be downcast to `T`. + #[cfg(feature = "kv_unstable")] + #[deprecated( + note = "downcasting has been removed; log an issue at https://github.com/rust-lang/log/issues if this is something you rely on" + )] + pub fn is<T: 'static>(&self) -> bool { + false + } + + /// Try downcast this value to `T`. + #[cfg(feature = "kv_unstable")] + #[deprecated( + note = "downcasting has been removed; log an issue at https://github.com/rust-lang/log/issues if this is something you rely on" + )] + pub fn downcast_ref<T: 'static>(&self) -> Option<&T> { + None + } +} + +// NOTE: Deprecated; but aliases can't carry this attribute +#[cfg(feature = "kv_unstable")] +pub use VisitValue as Visit; + +/// Get a value from a type implementing `std::fmt::Debug`. +#[cfg(feature = "kv_unstable")] +#[deprecated(note = "use the `key:? = value` macro syntax instead")] +#[macro_export] +macro_rules! as_debug { + ($capture:expr) => { + $crate::kv::Value::from_debug(&$capture) + }; +} + +/// Get a value from a type implementing `std::fmt::Display`. +#[cfg(feature = "kv_unstable")] +#[deprecated(note = "use the `key:% = value` macro syntax instead")] +#[macro_export] +macro_rules! as_display { + ($capture:expr) => { + $crate::kv::Value::from_display(&$capture) + }; +} + +/// Get a value from an error. +#[cfg(feature = "kv_unstable_std")] +#[deprecated(note = "use the `key:err = value` macro syntax instead")] +#[macro_export] +macro_rules! as_error { + ($capture:expr) => { + $crate::kv::Value::from_dyn_error(&$capture) + }; +} + +#[cfg(feature = "kv_unstable_serde")] +#[deprecated(note = "use the `key:serde = value` macro syntax instead")] +/// Get a value from a type implementing `serde::Serialize`. +#[macro_export] +macro_rules! as_serde { + ($capture:expr) => { + $crate::kv::Value::from_serde(&$capture) + }; +} + +/// Get a value from a type implementing `sval::Value`. +#[cfg(feature = "kv_unstable_sval")] +#[deprecated(note = "use the `key:sval = value` macro syntax instead")] +#[macro_export] +macro_rules! as_sval { + ($capture:expr) => { + $crate::kv::Value::from_sval(&$capture) + }; +} + +#[cfg(test)] +pub(crate) mod tests { + use super::*; + + impl<'v> Value<'v> { + pub(crate) fn to_token(&self) -> inner::Token { + self.inner.to_test_token() + } + } + + fn unsigned() -> impl Iterator<Item = Value<'static>> { + vec![ + Value::from(8u8), + Value::from(16u16), + Value::from(32u32), + Value::from(64u64), + Value::from(1usize), + Value::from(std::num::NonZeroU8::new(8).unwrap()), + Value::from(std::num::NonZeroU16::new(16).unwrap()), + Value::from(std::num::NonZeroU32::new(32).unwrap()), + Value::from(std::num::NonZeroU64::new(64).unwrap()), + Value::from(std::num::NonZeroUsize::new(1).unwrap()), + ] + .into_iter() + } + + fn signed() -> impl Iterator<Item = Value<'static>> { + vec![ + Value::from(-8i8), + Value::from(-16i16), + Value::from(-32i32), + Value::from(-64i64), + Value::from(-1isize), + Value::from(std::num::NonZeroI8::new(-8).unwrap()), + Value::from(std::num::NonZeroI16::new(-16).unwrap()), + Value::from(std::num::NonZeroI32::new(-32).unwrap()), + Value::from(std::num::NonZeroI64::new(-64).unwrap()), + Value::from(std::num::NonZeroIsize::new(-1).unwrap()), + ] + .into_iter() + } + + fn float() -> impl Iterator<Item = Value<'static>> { + vec![Value::from(32.32f32), Value::from(64.64f64)].into_iter() + } + + fn bool() -> impl Iterator<Item = Value<'static>> { + vec![Value::from(true), Value::from(false)].into_iter() + } + + fn str() -> impl Iterator<Item = Value<'static>> { + vec![Value::from("a string"), Value::from("a loong string")].into_iter() + } + + fn char() -> impl Iterator<Item = Value<'static>> { + vec![Value::from('a'), Value::from('â›°')].into_iter() + } + + #[test] + fn test_to_value_display() { + assert_eq!(42u64.to_value().to_string(), "42"); + assert_eq!(42i64.to_value().to_string(), "42"); + assert_eq!(42.01f64.to_value().to_string(), "42.01"); + assert_eq!(true.to_value().to_string(), "true"); + assert_eq!('a'.to_value().to_string(), "a"); + assert_eq!("a loong string".to_value().to_string(), "a loong string"); + assert_eq!(Some(true).to_value().to_string(), "true"); + assert_eq!(().to_value().to_string(), "None"); + assert_eq!(None::<bool>.to_value().to_string(), "None"); + } + + #[test] + fn test_to_value_structured() { + assert_eq!(42u64.to_value().to_token(), inner::Token::U64(42)); + assert_eq!(42i64.to_value().to_token(), inner::Token::I64(42)); + assert_eq!(42.01f64.to_value().to_token(), inner::Token::F64(42.01)); + assert_eq!(true.to_value().to_token(), inner::Token::Bool(true)); + assert_eq!('a'.to_value().to_token(), inner::Token::Char('a')); + assert_eq!( + "a loong string".to_value().to_token(), + inner::Token::Str("a loong string".into()) + ); + assert_eq!(Some(true).to_value().to_token(), inner::Token::Bool(true)); + assert_eq!(().to_value().to_token(), inner::Token::None); + assert_eq!(None::<bool>.to_value().to_token(), inner::Token::None); + } + + #[test] + fn test_to_number() { + for v in unsigned() { + assert!(v.to_u64().is_some()); + assert!(v.to_i64().is_some()); + } + + for v in signed() { + assert!(v.to_i64().is_some()); + } + + for v in unsigned().chain(signed()).chain(float()) { + assert!(v.to_f64().is_some()); + } + + for v in bool().chain(str()).chain(char()) { + assert!(v.to_u64().is_none()); + assert!(v.to_i64().is_none()); + assert!(v.to_f64().is_none()); + } + } + + #[test] + fn test_to_float() { + // Only integers from i32::MIN..=u32::MAX can be converted into floats + assert!(Value::from(i32::MIN).to_f64().is_some()); + assert!(Value::from(u32::MAX).to_f64().is_some()); + + assert!(Value::from((i32::MIN as i64) - 1).to_f64().is_none()); + assert!(Value::from((u32::MAX as u64) + 1).to_f64().is_none()); + } + + #[test] + fn test_to_cow_str() { + for v in str() { + assert!(v.to_borrowed_str().is_some()); + + #[cfg(feature = "kv_std")] + assert!(v.to_cow_str().is_some()); + } + + let short_lived = String::from("short lived"); + let v = Value::from(&*short_lived); + + assert!(v.to_borrowed_str().is_some()); + + #[cfg(feature = "kv_std")] + assert!(v.to_cow_str().is_some()); + + for v in unsigned().chain(signed()).chain(float()).chain(bool()) { + assert!(v.to_borrowed_str().is_none()); + + #[cfg(feature = "kv_std")] + assert!(v.to_cow_str().is_none()); + } + } + + #[test] + fn test_to_bool() { + for v in bool() { + assert!(v.to_bool().is_some()); + } + + for v in unsigned() + .chain(signed()) + .chain(float()) + .chain(str()) + .chain(char()) + { + assert!(v.to_bool().is_none()); + } + } + + #[test] + fn test_to_char() { + for v in char() { + assert!(v.to_char().is_some()); + } + + for v in unsigned() + .chain(signed()) + .chain(float()) + .chain(str()) + .chain(bool()) + { + assert!(v.to_char().is_none()); + } + } + + #[test] + fn test_visit_integer() { + struct Extract(Option<u64>); + + impl<'v> VisitValue<'v> for Extract { + fn visit_any(&mut self, value: Value) -> Result<(), Error> { + unimplemented!("unexpected value: {value:?}") + } + + fn visit_u64(&mut self, value: u64) -> Result<(), Error> { + self.0 = Some(value); + + Ok(()) + } + } + + let mut extract = Extract(None); + Value::from(42u64).visit(&mut extract).unwrap(); + + assert_eq!(Some(42), extract.0); + } + + #[test] + fn test_visit_borrowed_str() { + struct Extract<'v>(Option<&'v str>); + + impl<'v> VisitValue<'v> for Extract<'v> { + fn visit_any(&mut self, value: Value) -> Result<(), Error> { + unimplemented!("unexpected value: {value:?}") + } + + fn visit_borrowed_str(&mut self, value: &'v str) -> Result<(), Error> { + self.0 = Some(value); + + Ok(()) + } + } + + let mut extract = Extract(None); + + let short_lived = String::from("A short-lived string"); + Value::from(&*short_lived).visit(&mut extract).unwrap(); + + assert_eq!(Some("A short-lived string"), extract.0); + } +} diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/lib.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/lib.rs new file mode 100644 index 0000000..603bbac --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/lib.rs @@ -0,0 +1,1740 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A lightweight logging facade. +//! +//! The `log` crate provides a single logging API that abstracts over the +//! actual logging implementation. Libraries can use the logging API provided +//! by this crate, and the consumer of those libraries can choose the logging +//! implementation that is most suitable for its use case. +//! +//! If no logging implementation is selected, the facade falls back to a "noop" +//! implementation that ignores all log messages. The overhead in this case +//! is very small - just an integer load, comparison and jump. +//! +//! A log request consists of a _target_, a _level_, and a _body_. A target is a +//! string which defaults to the module path of the location of the log request, +//! though that default may be overridden. Logger implementations typically use +//! the target to filter requests based on some user configuration. +//! +//! # Usage +//! +//! The basic use of the log crate is through the five logging macros: [`error!`], +//! [`warn!`], [`info!`], [`debug!`] and [`trace!`] +//! where `error!` represents the highest-priority log messages +//! and `trace!` the lowest. The log messages are filtered by configuring +//! the log level to exclude messages with a lower priority. +//! Each of these macros accept format strings similarly to [`println!`]. +//! +//! +//! [`error!`]: ./macro.error.html +//! [`warn!`]: ./macro.warn.html +//! [`info!`]: ./macro.info.html +//! [`debug!`]: ./macro.debug.html +//! [`trace!`]: ./macro.trace.html +//! [`println!`]: https://doc.rust-lang.org/stable/std/macro.println.html +//! +//! Avoid writing expressions with side-effects in log statements. They may not be evaluated. +//! +//! ## In libraries +//! +//! Libraries should link only to the `log` crate, and use the provided +//! macros to log whatever information will be useful to downstream consumers. +//! +//! ### Examples +//! +//! ``` +//! # #[derive(Debug)] pub struct Yak(String); +//! # impl Yak { fn shave(&mut self, _: u32) {} } +//! # fn find_a_razor() -> Result<u32, u32> { Ok(1) } +//! use log::{info, warn}; +//! +//! pub fn shave_the_yak(yak: &mut Yak) { +//! info!(target: "yak_events", "Commencing yak shaving for {yak:?}"); +//! +//! loop { +//! match find_a_razor() { +//! Ok(razor) => { +//! info!("Razor located: {razor}"); +//! yak.shave(razor); +//! break; +//! } +//! Err(err) => { +//! warn!("Unable to locate a razor: {err}, retrying"); +//! } +//! } +//! } +//! } +//! # fn main() {} +//! ``` +//! +//! ## In executables +//! +//! Executables should choose a logging implementation and initialize it early in the +//! runtime of the program. Logging implementations will typically include a +//! function to do this. Any log messages generated before +//! the implementation is initialized will be ignored. +//! +//! The executable itself may use the `log` crate to log as well. +//! +//! ### Warning +//! +//! The logging system may only be initialized once. +//! +//! ## Structured logging +//! +//! If you enable the `kv` feature you can associate structured values +//! with your log records. If we take the example from before, we can include +//! some additional context besides what's in the formatted message: +//! +//! ``` +//! # use serde::Serialize; +//! # #[derive(Debug, Serialize)] pub struct Yak(String); +//! # impl Yak { fn shave(&mut self, _: u32) {} } +//! # fn find_a_razor() -> Result<u32, std::io::Error> { Ok(1) } +//! # #[cfg(feature = "kv_serde")] +//! # fn main() { +//! use log::{info, warn}; +//! +//! pub fn shave_the_yak(yak: &mut Yak) { +//! info!(target: "yak_events", yak:serde; "Commencing yak shaving"); +//! +//! loop { +//! match find_a_razor() { +//! Ok(razor) => { +//! info!(razor; "Razor located"); +//! yak.shave(razor); +//! break; +//! } +//! Err(e) => { +//! warn!(e:err; "Unable to locate a razor, retrying"); +//! } +//! } +//! } +//! } +//! # } +//! # #[cfg(not(feature = "kv_serde"))] +//! # fn main() {} +//! ``` +//! +//! See the [`kv`] module documentation for more details. +//! +//! # Available logging implementations +//! +//! In order to produce log output executables have to use +//! a logger implementation compatible with the facade. +//! There are many available implementations to choose from, +//! here are some of the most popular ones: +//! +//! * Simple minimal loggers: +//! * [env_logger] +//! * [colog] +//! * [simple_logger] +//! * [simplelog] +//! * [pretty_env_logger] +//! * [stderrlog] +//! * [flexi_logger] +//! * [call_logger] +//! * [structured-logger] +//! * Complex configurable frameworks: +//! * [log4rs] +//! * [fern] +//! * Adaptors for other facilities: +//! * [syslog] +//! * [slog-stdlog] +//! * [systemd-journal-logger] +//! * [android_log] +//! * [win_dbg_logger] +//! * [db_logger] +//! * [log-to-defmt] +//! * [logcontrol-log] +//! * For WebAssembly binaries: +//! * [console_log] +//! * For dynamic libraries: +//! * You may need to construct an FFI-safe wrapper over `log` to initialize in your libraries +//! * Utilities: +//! * [log_err] +//! * [log-reload] +//! +//! # Implementing a Logger +//! +//! Loggers implement the [`Log`] trait. Here's a very basic example that simply +//! logs all messages at the [`Error`][level_link], [`Warn`][level_link] or +//! [`Info`][level_link] levels to stdout: +//! +//! ``` +//! use log::{Record, Level, Metadata}; +//! +//! struct SimpleLogger; +//! +//! impl log::Log for SimpleLogger { +//! fn enabled(&self, metadata: &Metadata) -> bool { +//! metadata.level() <= Level::Info +//! } +//! +//! fn log(&self, record: &Record) { +//! if self.enabled(record.metadata()) { +//! println!("{} - {}", record.level(), record.args()); +//! } +//! } +//! +//! fn flush(&self) {} +//! } +//! +//! # fn main() {} +//! ``` +//! +//! Loggers are installed by calling the [`set_logger`] function. The maximum +//! log level also needs to be adjusted via the [`set_max_level`] function. The +//! logging facade uses this as an optimization to improve performance of log +//! messages at levels that are disabled. It's important to set it, as it +//! defaults to [`Off`][filter_link], so no log messages will ever be captured! +//! In the case of our example logger, we'll want to set the maximum log level +//! to [`Info`][filter_link], since we ignore any [`Debug`][level_link] or +//! [`Trace`][level_link] level log messages. A logging implementation should +//! provide a function that wraps a call to [`set_logger`] and +//! [`set_max_level`], handling initialization of the logger: +//! +//! ``` +//! # use log::{Level, Metadata}; +//! # struct SimpleLogger; +//! # impl log::Log for SimpleLogger { +//! # fn enabled(&self, _: &Metadata) -> bool { false } +//! # fn log(&self, _: &log::Record) {} +//! # fn flush(&self) {} +//! # } +//! # fn main() {} +//! use log::{SetLoggerError, LevelFilter}; +//! +//! static LOGGER: SimpleLogger = SimpleLogger; +//! +//! pub fn init() -> Result<(), SetLoggerError> { +//! log::set_logger(&LOGGER) +//! .map(|()| log::set_max_level(LevelFilter::Info)) +//! } +//! ``` +//! +//! Implementations that adjust their configurations at runtime should take care +//! to adjust the maximum log level as well. +//! +//! # Use with `std` +//! +//! `set_logger` requires you to provide a `&'static Log`, which can be hard to +//! obtain if your logger depends on some runtime configuration. The +//! `set_boxed_logger` function is available with the `std` Cargo feature. It is +//! identical to `set_logger` except that it takes a `Box<Log>` rather than a +//! `&'static Log`: +//! +//! ``` +//! # use log::{Level, LevelFilter, Log, SetLoggerError, Metadata}; +//! # struct SimpleLogger; +//! # impl log::Log for SimpleLogger { +//! # fn enabled(&self, _: &Metadata) -> bool { false } +//! # fn log(&self, _: &log::Record) {} +//! # fn flush(&self) {} +//! # } +//! # fn main() {} +//! # #[cfg(feature = "std")] +//! pub fn init() -> Result<(), SetLoggerError> { +//! log::set_boxed_logger(Box::new(SimpleLogger)) +//! .map(|()| log::set_max_level(LevelFilter::Info)) +//! } +//! ``` +//! +//! # Compile time filters +//! +//! Log levels can be statically disabled at compile time by enabling one of these Cargo features: +//! +//! * `max_level_off` +//! * `max_level_error` +//! * `max_level_warn` +//! * `max_level_info` +//! * `max_level_debug` +//! * `max_level_trace` +//! +//! Log invocations at disabled levels will be skipped and will not even be present in the +//! resulting binary. These features control the value of the `STATIC_MAX_LEVEL` constant. The +//! logging macros check this value before logging a message. By default, no levels are disabled. +//! +//! It is possible to override this level for release builds only with the following features: +//! +//! * `release_max_level_off` +//! * `release_max_level_error` +//! * `release_max_level_warn` +//! * `release_max_level_info` +//! * `release_max_level_debug` +//! * `release_max_level_trace` +//! +//! Libraries should avoid using the max level features because they're global and can't be changed +//! once they're set. +//! +//! For example, a crate can disable trace level logs in debug builds and trace, debug, and info +//! level logs in release builds with the following configuration: +//! +//! ```toml +//! [dependencies] +//! log = { version = "0.4", features = ["max_level_debug", "release_max_level_warn"] } +//! ``` +//! # Crate Feature Flags +//! +//! The following crate feature flags are available in addition to the filters. They are +//! configured in your `Cargo.toml`. +//! +//! * `std` allows use of `std` crate instead of the default `core`. Enables using `std::error` and +//! `set_boxed_logger` functionality. +//! * `serde` enables support for serialization and deserialization of `Level` and `LevelFilter`. +//! +//! ```toml +//! [dependencies] +//! log = { version = "0.4", features = ["std", "serde"] } +//! ``` +//! +//! # Version compatibility +//! +//! The 0.3 and 0.4 versions of the `log` crate are almost entirely compatible. Log messages +//! made using `log` 0.3 will forward transparently to a logger implementation using `log` 0.4. Log +//! messages made using `log` 0.4 will forward to a logger implementation using `log` 0.3, but the +//! module path and file name information associated with the message will unfortunately be lost. +//! +//! [`Log`]: trait.Log.html +//! [level_link]: enum.Level.html +//! [filter_link]: enum.LevelFilter.html +//! [`set_logger`]: fn.set_logger.html +//! [`set_max_level`]: fn.set_max_level.html +//! [`try_set_logger_raw`]: fn.try_set_logger_raw.html +//! [`shutdown_logger_raw`]: fn.shutdown_logger_raw.html +//! [env_logger]: https://docs.rs/env_logger/*/env_logger/ +//! [colog]: https://docs.rs/colog/*/colog/ +//! [simple_logger]: https://github.com/borntyping/rust-simple_logger +//! [simplelog]: https://github.com/drakulix/simplelog.rs +//! [pretty_env_logger]: https://docs.rs/pretty_env_logger/*/pretty_env_logger/ +//! [stderrlog]: https://docs.rs/stderrlog/*/stderrlog/ +//! [flexi_logger]: https://docs.rs/flexi_logger/*/flexi_logger/ +//! [call_logger]: https://docs.rs/call_logger/*/call_logger/ +//! [syslog]: https://docs.rs/syslog/*/syslog/ +//! [slog-stdlog]: https://docs.rs/slog-stdlog/*/slog_stdlog/ +//! [log4rs]: https://docs.rs/log4rs/*/log4rs/ +//! [fern]: https://docs.rs/fern/*/fern/ +//! [systemd-journal-logger]: https://docs.rs/systemd-journal-logger/*/systemd_journal_logger/ +//! [android_log]: https://docs.rs/android_log/*/android_log/ +//! [win_dbg_logger]: https://docs.rs/win_dbg_logger/*/win_dbg_logger/ +//! [db_logger]: https://docs.rs/db_logger/*/db_logger/ +//! [log-to-defmt]: https://docs.rs/log-to-defmt/*/log_to_defmt/ +//! [console_log]: https://docs.rs/console_log/*/console_log/ +//! [structured-logger]: https://docs.rs/structured-logger/latest/structured_logger/ +//! [logcontrol-log]: https://docs.rs/logcontrol-log/*/logcontrol_log/ +//! [log_err]: https://docs.rs/log_err/*/log_err/ +//! [log-reload]: https://docs.rs/log-reload/*/log_reload/ + +#![doc( + html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", + html_favicon_url = "https://www.rust-lang.org/favicon.ico", + html_root_url = "https://docs.rs/log/0.4.22" +)] +#![warn(missing_docs)] +#![deny(missing_debug_implementations, unconditional_recursion)] +#![cfg_attr(all(not(feature = "std"), not(test)), no_std)] + +#[cfg(any( + all(feature = "max_level_off", feature = "max_level_error"), + all(feature = "max_level_off", feature = "max_level_warn"), + all(feature = "max_level_off", feature = "max_level_info"), + all(feature = "max_level_off", feature = "max_level_debug"), + all(feature = "max_level_off", feature = "max_level_trace"), + all(feature = "max_level_error", feature = "max_level_warn"), + all(feature = "max_level_error", feature = "max_level_info"), + all(feature = "max_level_error", feature = "max_level_debug"), + all(feature = "max_level_error", feature = "max_level_trace"), + all(feature = "max_level_warn", feature = "max_level_info"), + all(feature = "max_level_warn", feature = "max_level_debug"), + all(feature = "max_level_warn", feature = "max_level_trace"), + all(feature = "max_level_info", feature = "max_level_debug"), + all(feature = "max_level_info", feature = "max_level_trace"), + all(feature = "max_level_debug", feature = "max_level_trace"), +))] +compile_error!("multiple max_level_* features set"); + +#[rustfmt::skip] +#[cfg(any( + all(feature = "release_max_level_off", feature = "release_max_level_error"), + all(feature = "release_max_level_off", feature = "release_max_level_warn"), + all(feature = "release_max_level_off", feature = "release_max_level_info"), + all(feature = "release_max_level_off", feature = "release_max_level_debug"), + all(feature = "release_max_level_off", feature = "release_max_level_trace"), + all(feature = "release_max_level_error", feature = "release_max_level_warn"), + all(feature = "release_max_level_error", feature = "release_max_level_info"), + all(feature = "release_max_level_error", feature = "release_max_level_debug"), + all(feature = "release_max_level_error", feature = "release_max_level_trace"), + all(feature = "release_max_level_warn", feature = "release_max_level_info"), + all(feature = "release_max_level_warn", feature = "release_max_level_debug"), + all(feature = "release_max_level_warn", feature = "release_max_level_trace"), + all(feature = "release_max_level_info", feature = "release_max_level_debug"), + all(feature = "release_max_level_info", feature = "release_max_level_trace"), + all(feature = "release_max_level_debug", feature = "release_max_level_trace"), +))] +compile_error!("multiple release_max_level_* features set"); + +#[cfg(all(not(feature = "std"), not(test)))] +extern crate core as std; + +use std::cfg; +#[cfg(feature = "std")] +use std::error; +use std::str::FromStr; +use std::{cmp, fmt, mem}; + +#[macro_use] +mod macros; +mod serde; + +#[cfg(feature = "kv")] +pub mod kv; + +use std::cell::Cell; +use std::sync::atomic::Ordering; + +struct AtomicUsize { + v: Cell<usize>, +} + +impl AtomicUsize { + const fn new(v: usize) -> AtomicUsize { + AtomicUsize { v: Cell::new(v) } + } + + fn load(&self, _order: Ordering) -> usize { + self.v.get() + } + + fn store(&self, val: usize, _order: Ordering) { + self.v.set(val) + } +} + +// Any platform without atomics is unlikely to have multiple cores, so +// writing via Cell will not be a race condition. +unsafe impl Sync for AtomicUsize {} + +// The LOGGER static holds a pointer to the global logger. It is protected by +// the STATE static which determines whether LOGGER has been initialized yet. +static mut LOGGER: &dyn Log = &NopLogger; + +static STATE: AtomicUsize = AtomicUsize::new(0); + +// There are three different states that we care about: the logger's +// uninitialized, the logger's initializing (set_logger's been called but +// LOGGER hasn't actually been set yet), or the logger's active. +const UNINITIALIZED: usize = 0; +const INITIALIZING: usize = 1; +const INITIALIZED: usize = 2; + +static MAX_LOG_LEVEL_FILTER: AtomicUsize = AtomicUsize::new(0); + +static LOG_LEVEL_NAMES: [&str; 6] = ["OFF", "ERROR", "WARN", "INFO", "DEBUG", "TRACE"]; + +static SET_LOGGER_ERROR: &str = "attempted to set a logger after the logging system \ + was already initialized"; +static LEVEL_PARSE_ERROR: &str = + "attempted to convert a string that doesn't match an existing log level"; + +/// An enum representing the available verbosity levels of the logger. +/// +/// Typical usage includes: checking if a certain `Level` is enabled with +/// [`log_enabled!`](macro.log_enabled.html), specifying the `Level` of +/// [`log!`](macro.log.html), and comparing a `Level` directly to a +/// [`LevelFilter`](enum.LevelFilter.html). +#[repr(usize)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] +pub enum Level { + /// The "error" level. + /// + /// Designates very serious errors. + // This way these line up with the discriminants for LevelFilter below + // This works because Rust treats field-less enums the same way as C does: + // https://doc.rust-lang.org/reference/items/enumerations.html#custom-discriminant-values-for-field-less-enumerations + Error = 1, + /// The "warn" level. + /// + /// Designates hazardous situations. + Warn, + /// The "info" level. + /// + /// Designates useful information. + Info, + /// The "debug" level. + /// + /// Designates lower priority information. + Debug, + /// The "trace" level. + /// + /// Designates very low priority, often extremely verbose, information. + Trace, +} + +impl PartialEq<LevelFilter> for Level { + #[inline] + fn eq(&self, other: &LevelFilter) -> bool { + *self as usize == *other as usize + } +} + +impl PartialOrd<LevelFilter> for Level { + #[inline] + fn partial_cmp(&self, other: &LevelFilter) -> Option<cmp::Ordering> { + Some((*self as usize).cmp(&(*other as usize))) + } +} + +impl FromStr for Level { + type Err = ParseLevelError; + fn from_str(level: &str) -> Result<Level, Self::Err> { + LOG_LEVEL_NAMES + .iter() + .position(|&name| name.eq_ignore_ascii_case(level)) + .into_iter() + .filter(|&idx| idx != 0) + .map(|idx| Level::from_usize(idx).unwrap()) + .next() + .ok_or(ParseLevelError(())) + } +} + +impl fmt::Display for Level { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.pad(self.as_str()) + } +} + +impl Level { + fn from_usize(u: usize) -> Option<Level> { + match u { + 1 => Some(Level::Error), + 2 => Some(Level::Warn), + 3 => Some(Level::Info), + 4 => Some(Level::Debug), + 5 => Some(Level::Trace), + _ => None, + } + } + + /// Returns the most verbose logging level. + #[inline] + pub fn max() -> Level { + Level::Trace + } + + /// Converts the `Level` to the equivalent `LevelFilter`. + #[inline] + pub fn to_level_filter(&self) -> LevelFilter { + LevelFilter::from_usize(*self as usize).unwrap() + } + + /// Returns the string representation of the `Level`. + /// + /// This returns the same string as the `fmt::Display` implementation. + pub fn as_str(&self) -> &'static str { + LOG_LEVEL_NAMES[*self as usize] + } + + /// Iterate through all supported logging levels. + /// + /// The order of iteration is from more severe to less severe log messages. + /// + /// # Examples + /// + /// ``` + /// use log::Level; + /// + /// let mut levels = Level::iter(); + /// + /// assert_eq!(Some(Level::Error), levels.next()); + /// assert_eq!(Some(Level::Trace), levels.last()); + /// ``` + pub fn iter() -> impl Iterator<Item = Self> { + (1..6).map(|i| Self::from_usize(i).unwrap()) + } +} + +/// An enum representing the available verbosity level filters of the logger. +/// +/// A `LevelFilter` may be compared directly to a [`Level`]. Use this type +/// to get and set the maximum log level with [`max_level()`] and [`set_max_level`]. +/// +/// [`Level`]: enum.Level.html +/// [`max_level()`]: fn.max_level.html +/// [`set_max_level`]: fn.set_max_level.html +#[repr(usize)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] +pub enum LevelFilter { + /// A level lower than all log levels. + Off, + /// Corresponds to the `Error` log level. + Error, + /// Corresponds to the `Warn` log level. + Warn, + /// Corresponds to the `Info` log level. + Info, + /// Corresponds to the `Debug` log level. + Debug, + /// Corresponds to the `Trace` log level. + Trace, +} + +impl PartialEq<Level> for LevelFilter { + #[inline] + fn eq(&self, other: &Level) -> bool { + other.eq(self) + } +} + +impl PartialOrd<Level> for LevelFilter { + #[inline] + fn partial_cmp(&self, other: &Level) -> Option<cmp::Ordering> { + Some((*self as usize).cmp(&(*other as usize))) + } +} + +impl FromStr for LevelFilter { + type Err = ParseLevelError; + fn from_str(level: &str) -> Result<LevelFilter, Self::Err> { + LOG_LEVEL_NAMES + .iter() + .position(|&name| name.eq_ignore_ascii_case(level)) + .map(|p| LevelFilter::from_usize(p).unwrap()) + .ok_or(ParseLevelError(())) + } +} + +impl fmt::Display for LevelFilter { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.pad(self.as_str()) + } +} + +impl LevelFilter { + fn from_usize(u: usize) -> Option<LevelFilter> { + match u { + 0 => Some(LevelFilter::Off), + 1 => Some(LevelFilter::Error), + 2 => Some(LevelFilter::Warn), + 3 => Some(LevelFilter::Info), + 4 => Some(LevelFilter::Debug), + 5 => Some(LevelFilter::Trace), + _ => None, + } + } + + /// Returns the most verbose logging level filter. + #[inline] + pub fn max() -> LevelFilter { + LevelFilter::Trace + } + + /// Converts `self` to the equivalent `Level`. + /// + /// Returns `None` if `self` is `LevelFilter::Off`. + #[inline] + pub fn to_level(&self) -> Option<Level> { + Level::from_usize(*self as usize) + } + + /// Returns the string representation of the `LevelFilter`. + /// + /// This returns the same string as the `fmt::Display` implementation. + pub fn as_str(&self) -> &'static str { + LOG_LEVEL_NAMES[*self as usize] + } + + /// Iterate through all supported filtering levels. + /// + /// The order of iteration is from less to more verbose filtering. + /// + /// # Examples + /// + /// ``` + /// use log::LevelFilter; + /// + /// let mut levels = LevelFilter::iter(); + /// + /// assert_eq!(Some(LevelFilter::Off), levels.next()); + /// assert_eq!(Some(LevelFilter::Trace), levels.last()); + /// ``` + pub fn iter() -> impl Iterator<Item = Self> { + (0..6).map(|i| Self::from_usize(i).unwrap()) + } +} + +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] +enum MaybeStaticStr<'a> { + Static(&'static str), + Borrowed(&'a str), +} + +impl<'a> MaybeStaticStr<'a> { + #[inline] + fn get(&self) -> &'a str { + match *self { + MaybeStaticStr::Static(s) => s, + MaybeStaticStr::Borrowed(s) => s, + } + } +} + +/// The "payload" of a log message. +/// +/// # Use +/// +/// `Record` structures are passed as parameters to the [`log`][method.log] +/// method of the [`Log`] trait. Logger implementors manipulate these +/// structures in order to display log messages. `Record`s are automatically +/// created by the [`log!`] macro and so are not seen by log users. +/// +/// Note that the [`level()`] and [`target()`] accessors are equivalent to +/// `self.metadata().level()` and `self.metadata().target()` respectively. +/// These methods are provided as a convenience for users of this structure. +/// +/// # Example +/// +/// The following example shows a simple logger that displays the level, +/// module path, and message of any `Record` that is passed to it. +/// +/// ``` +/// struct SimpleLogger; +/// +/// impl log::Log for SimpleLogger { +/// fn enabled(&self, _metadata: &log::Metadata) -> bool { +/// true +/// } +/// +/// fn log(&self, record: &log::Record) { +/// if !self.enabled(record.metadata()) { +/// return; +/// } +/// +/// println!("{}:{} -- {}", +/// record.level(), +/// record.target(), +/// record.args()); +/// } +/// fn flush(&self) {} +/// } +/// ``` +/// +/// [method.log]: trait.Log.html#tymethod.log +/// [`Log`]: trait.Log.html +/// [`log!`]: macro.log.html +/// [`level()`]: struct.Record.html#method.level +/// [`target()`]: struct.Record.html#method.target +#[derive(Clone, Debug)] +pub struct Record<'a> { + metadata: Metadata<'a>, + args: fmt::Arguments<'a>, + module_path: Option<MaybeStaticStr<'a>>, + file: Option<MaybeStaticStr<'a>>, + line: Option<u32>, + #[cfg(feature = "kv")] + key_values: KeyValues<'a>, +} + +// This wrapper type is only needed so we can +// `#[derive(Debug)]` on `Record`. It also +// provides a useful `Debug` implementation for +// the underlying `Source`. +#[cfg(feature = "kv")] +#[derive(Clone)] +struct KeyValues<'a>(&'a dyn kv::Source); + +#[cfg(feature = "kv")] +impl<'a> fmt::Debug for KeyValues<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut visitor = f.debug_map(); + self.0.visit(&mut visitor).map_err(|_| fmt::Error)?; + visitor.finish() + } +} + +impl<'a> Record<'a> { + /// Returns a new builder. + #[inline] + pub fn builder() -> RecordBuilder<'a> { + RecordBuilder::new() + } + + /// The message body. + #[inline] + pub fn args(&self) -> &fmt::Arguments<'a> { + &self.args + } + + /// Metadata about the log directive. + #[inline] + pub fn metadata(&self) -> &Metadata<'a> { + &self.metadata + } + + /// The verbosity level of the message. + #[inline] + pub fn level(&self) -> Level { + self.metadata.level() + } + + /// The name of the target of the directive. + #[inline] + pub fn target(&self) -> &'a str { + self.metadata.target() + } + + /// The module path of the message. + #[inline] + pub fn module_path(&self) -> Option<&'a str> { + self.module_path.map(|s| s.get()) + } + + /// The module path of the message, if it is a `'static` string. + #[inline] + pub fn module_path_static(&self) -> Option<&'static str> { + match self.module_path { + Some(MaybeStaticStr::Static(s)) => Some(s), + _ => None, + } + } + + /// The source file containing the message. + #[inline] + pub fn file(&self) -> Option<&'a str> { + self.file.map(|s| s.get()) + } + + /// The source file containing the message, if it is a `'static` string. + #[inline] + pub fn file_static(&self) -> Option<&'static str> { + match self.file { + Some(MaybeStaticStr::Static(s)) => Some(s), + _ => None, + } + } + + /// The line containing the message. + #[inline] + pub fn line(&self) -> Option<u32> { + self.line + } + + /// The structured key-value pairs associated with the message. + #[cfg(feature = "kv")] + #[inline] + pub fn key_values(&self) -> &dyn kv::Source { + self.key_values.0 + } + + /// Create a new [`RecordBuilder`](struct.RecordBuilder.html) based on this record. + #[cfg(feature = "kv")] + #[inline] + pub fn to_builder(&self) -> RecordBuilder { + RecordBuilder { + record: Record { + metadata: Metadata { + level: self.metadata.level, + target: self.metadata.target, + }, + args: self.args, + module_path: self.module_path, + file: self.file, + line: self.line, + key_values: self.key_values.clone(), + }, + } + } +} + +/// Builder for [`Record`](struct.Record.html). +/// +/// Typically should only be used by log library creators or for testing and "shim loggers". +/// The `RecordBuilder` can set the different parameters of `Record` object, and returns +/// the created object when `build` is called. +/// +/// # Examples +/// +/// ``` +/// use log::{Level, Record}; +/// +/// let record = Record::builder() +/// .args(format_args!("Error!")) +/// .level(Level::Error) +/// .target("myApp") +/// .file(Some("server.rs")) +/// .line(Some(144)) +/// .module_path(Some("server")) +/// .build(); +/// ``` +/// +/// Alternatively, use [`MetadataBuilder`](struct.MetadataBuilder.html): +/// +/// ``` +/// use log::{Record, Level, MetadataBuilder}; +/// +/// let error_metadata = MetadataBuilder::new() +/// .target("myApp") +/// .level(Level::Error) +/// .build(); +/// +/// let record = Record::builder() +/// .metadata(error_metadata) +/// .args(format_args!("Error!")) +/// .line(Some(433)) +/// .file(Some("app.rs")) +/// .module_path(Some("server")) +/// .build(); +/// ``` +#[derive(Debug)] +pub struct RecordBuilder<'a> { + record: Record<'a>, +} + +impl<'a> RecordBuilder<'a> { + /// Construct new `RecordBuilder`. + /// + /// The default options are: + /// + /// - `args`: [`format_args!("")`] + /// - `metadata`: [`Metadata::builder().build()`] + /// - `module_path`: `None` + /// - `file`: `None` + /// - `line`: `None` + /// + /// [`format_args!("")`]: https://doc.rust-lang.org/std/macro.format_args.html + /// [`Metadata::builder().build()`]: struct.MetadataBuilder.html#method.build + #[inline] + pub fn new() -> RecordBuilder<'a> { + RecordBuilder { + record: Record { + args: format_args!(""), + metadata: Metadata::builder().build(), + module_path: None, + file: None, + line: None, + #[cfg(feature = "kv")] + key_values: KeyValues(&None::<(kv::Key, kv::Value)>), + }, + } + } + + /// Set [`args`](struct.Record.html#method.args). + #[inline] + pub fn args(&mut self, args: fmt::Arguments<'a>) -> &mut RecordBuilder<'a> { + self.record.args = args; + self + } + + /// Set [`metadata`](struct.Record.html#method.metadata). Construct a `Metadata` object with [`MetadataBuilder`](struct.MetadataBuilder.html). + #[inline] + pub fn metadata(&mut self, metadata: Metadata<'a>) -> &mut RecordBuilder<'a> { + self.record.metadata = metadata; + self + } + + /// Set [`Metadata::level`](struct.Metadata.html#method.level). + #[inline] + pub fn level(&mut self, level: Level) -> &mut RecordBuilder<'a> { + self.record.metadata.level = level; + self + } + + /// Set [`Metadata::target`](struct.Metadata.html#method.target) + #[inline] + pub fn target(&mut self, target: &'a str) -> &mut RecordBuilder<'a> { + self.record.metadata.target = target; + self + } + + /// Set [`module_path`](struct.Record.html#method.module_path) + #[inline] + pub fn module_path(&mut self, path: Option<&'a str>) -> &mut RecordBuilder<'a> { + self.record.module_path = path.map(MaybeStaticStr::Borrowed); + self + } + + /// Set [`module_path`](struct.Record.html#method.module_path) to a `'static` string + #[inline] + pub fn module_path_static(&mut self, path: Option<&'static str>) -> &mut RecordBuilder<'a> { + self.record.module_path = path.map(MaybeStaticStr::Static); + self + } + + /// Set [`file`](struct.Record.html#method.file) + #[inline] + pub fn file(&mut self, file: Option<&'a str>) -> &mut RecordBuilder<'a> { + self.record.file = file.map(MaybeStaticStr::Borrowed); + self + } + + /// Set [`file`](struct.Record.html#method.file) to a `'static` string. + #[inline] + pub fn file_static(&mut self, file: Option<&'static str>) -> &mut RecordBuilder<'a> { + self.record.file = file.map(MaybeStaticStr::Static); + self + } + + /// Set [`line`](struct.Record.html#method.line) + #[inline] + pub fn line(&mut self, line: Option<u32>) -> &mut RecordBuilder<'a> { + self.record.line = line; + self + } + + /// Set [`key_values`](struct.Record.html#method.key_values) + #[cfg(feature = "kv")] + #[inline] + pub fn key_values(&mut self, kvs: &'a dyn kv::Source) -> &mut RecordBuilder<'a> { + self.record.key_values = KeyValues(kvs); + self + } + + /// Invoke the builder and return a `Record` + #[inline] + pub fn build(&self) -> Record<'a> { + self.record.clone() + } +} + +impl<'a> Default for RecordBuilder<'a> { + fn default() -> Self { + Self::new() + } +} + +/// Metadata about a log message. +/// +/// # Use +/// +/// `Metadata` structs are created when users of the library use +/// logging macros. +/// +/// They are consumed by implementations of the `Log` trait in the +/// `enabled` method. +/// +/// `Record`s use `Metadata` to determine the log message's severity +/// and target. +/// +/// Users should use the `log_enabled!` macro in their code to avoid +/// constructing expensive log messages. +/// +/// # Examples +/// +/// ``` +/// use log::{Record, Level, Metadata}; +/// +/// struct MyLogger; +/// +/// impl log::Log for MyLogger { +/// fn enabled(&self, metadata: &Metadata) -> bool { +/// metadata.level() <= Level::Info +/// } +/// +/// fn log(&self, record: &Record) { +/// if self.enabled(record.metadata()) { +/// println!("{} - {}", record.level(), record.args()); +/// } +/// } +/// fn flush(&self) {} +/// } +/// +/// # fn main(){} +/// ``` +#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] +pub struct Metadata<'a> { + level: Level, + target: &'a str, +} + +impl<'a> Metadata<'a> { + /// Returns a new builder. + #[inline] + pub fn builder() -> MetadataBuilder<'a> { + MetadataBuilder::new() + } + + /// The verbosity level of the message. + #[inline] + pub fn level(&self) -> Level { + self.level + } + + /// The name of the target of the directive. + #[inline] + pub fn target(&self) -> &'a str { + self.target + } +} + +/// Builder for [`Metadata`](struct.Metadata.html). +/// +/// Typically should only be used by log library creators or for testing and "shim loggers". +/// The `MetadataBuilder` can set the different parameters of a `Metadata` object, and returns +/// the created object when `build` is called. +/// +/// # Example +/// +/// ``` +/// let target = "myApp"; +/// use log::{Level, MetadataBuilder}; +/// let metadata = MetadataBuilder::new() +/// .level(Level::Debug) +/// .target(target) +/// .build(); +/// ``` +#[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] +pub struct MetadataBuilder<'a> { + metadata: Metadata<'a>, +} + +impl<'a> MetadataBuilder<'a> { + /// Construct a new `MetadataBuilder`. + /// + /// The default options are: + /// + /// - `level`: `Level::Info` + /// - `target`: `""` + #[inline] + pub fn new() -> MetadataBuilder<'a> { + MetadataBuilder { + metadata: Metadata { + level: Level::Info, + target: "", + }, + } + } + + /// Setter for [`level`](struct.Metadata.html#method.level). + #[inline] + pub fn level(&mut self, arg: Level) -> &mut MetadataBuilder<'a> { + self.metadata.level = arg; + self + } + + /// Setter for [`target`](struct.Metadata.html#method.target). + #[inline] + pub fn target(&mut self, target: &'a str) -> &mut MetadataBuilder<'a> { + self.metadata.target = target; + self + } + + /// Returns a `Metadata` object. + #[inline] + pub fn build(&self) -> Metadata<'a> { + self.metadata.clone() + } +} + +impl<'a> Default for MetadataBuilder<'a> { + fn default() -> Self { + Self::new() + } +} + +/// A trait encapsulating the operations required of a logger. +pub trait Log: Sync + Send { + /// Determines if a log message with the specified metadata would be + /// logged. + /// + /// This is used by the `log_enabled!` macro to allow callers to avoid + /// expensive computation of log message arguments if the message would be + /// discarded anyway. + /// + /// # For implementors + /// + /// This method isn't called automatically by the `log!` macros. + /// It's up to an implementation of the `Log` trait to call `enabled` in its own + /// `log` method implementation to guarantee that filtering is applied. + fn enabled(&self, metadata: &Metadata) -> bool; + + /// Logs the `Record`. + /// + /// # For implementors + /// + /// Note that `enabled` is *not* necessarily called before this method. + /// Implementations of `log` should perform all necessary filtering + /// internally. + fn log(&self, record: &Record); + + /// Flushes any buffered records. + /// + /// # For implementors + /// + /// This method isn't called automatically by the `log!` macros. + /// It can be called manually on shut-down to ensure any in-flight records are flushed. + fn flush(&self); +} + +// Just used as a dummy initial value for LOGGER +struct NopLogger; + +impl Log for NopLogger { + fn enabled(&self, _: &Metadata) -> bool { + false + } + + fn log(&self, _: &Record) {} + fn flush(&self) {} +} + +impl<T> Log for &'_ T +where + T: ?Sized + Log, +{ + fn enabled(&self, metadata: &Metadata) -> bool { + (**self).enabled(metadata) + } + + fn log(&self, record: &Record) { + (**self).log(record); + } + fn flush(&self) { + (**self).flush(); + } +} + +#[cfg(feature = "std")] +impl<T> Log for std::boxed::Box<T> +where + T: ?Sized + Log, +{ + fn enabled(&self, metadata: &Metadata) -> bool { + self.as_ref().enabled(metadata) + } + + fn log(&self, record: &Record) { + self.as_ref().log(record); + } + fn flush(&self) { + self.as_ref().flush(); + } +} + +#[cfg(feature = "std")] +impl<T> Log for std::sync::Arc<T> +where + T: ?Sized + Log, +{ + fn enabled(&self, metadata: &Metadata) -> bool { + self.as_ref().enabled(metadata) + } + + fn log(&self, record: &Record) { + self.as_ref().log(record); + } + fn flush(&self) { + self.as_ref().flush(); + } +} + +/// A thread-unsafe version of [`set_max_level`]. +/// +/// This function is available on all platforms, even those that do not have +/// support for atomics that is needed by [`set_max_level`]. +/// +/// In almost all cases, [`set_max_level`] should be preferred. +/// +/// # Safety +/// +/// This function is only safe to call when it cannot race with any other +/// calls to `set_max_level` or `set_max_level_racy`. +/// +/// This can be upheld by (for example) making sure that **there are no other +/// threads**, and (on embedded) that **interrupts are disabled**. +/// +/// It is safe to use all other logging functions while this function runs +/// (including all logging macros). +/// +/// [`set_max_level`]: fn.set_max_level.html +#[inline] +pub unsafe fn set_max_level_racy(level: LevelFilter) { + // `MAX_LOG_LEVEL_FILTER` uses a `Cell` as the underlying primitive when a + // platform doesn't support `target_has_atomic = "ptr"`, so even though this looks the same + // as `set_max_level` it may have different safety properties. + MAX_LOG_LEVEL_FILTER.store(level as usize, Ordering::Relaxed); +} + +/// Returns the current maximum log level. +/// +/// The [`log!`], [`error!`], [`warn!`], [`info!`], [`debug!`], and [`trace!`] macros check +/// this value and discard any message logged at a higher level. The maximum +/// log level is set by the [`set_max_level`] function. +/// +/// [`log!`]: macro.log.html +/// [`error!`]: macro.error.html +/// [`warn!`]: macro.warn.html +/// [`info!`]: macro.info.html +/// [`debug!`]: macro.debug.html +/// [`trace!`]: macro.trace.html +/// [`set_max_level`]: fn.set_max_level.html +#[inline(always)] +pub fn max_level() -> LevelFilter { + // Since `LevelFilter` is `repr(usize)`, + // this transmute is sound if and only if `MAX_LOG_LEVEL_FILTER` + // is set to a usize that is a valid discriminant for `LevelFilter`. + // Since `MAX_LOG_LEVEL_FILTER` is private, the only time it's set + // is by `set_max_level` above, i.e. by casting a `LevelFilter` to `usize`. + // So any usize stored in `MAX_LOG_LEVEL_FILTER` is a valid discriminant. + unsafe { mem::transmute(MAX_LOG_LEVEL_FILTER.load(Ordering::Relaxed)) } +} + +/// A thread-unsafe version of [`set_logger`]. +/// +/// This function is available on all platforms, even those that do not have +/// support for atomics that is needed by [`set_logger`]. +/// +/// In almost all cases, [`set_logger`] should be preferred. +/// +/// # Safety +/// +/// This function is only safe to call when it cannot race with any other +/// calls to `set_logger` or `set_logger_racy`. +/// +/// This can be upheld by (for example) making sure that **there are no other +/// threads**, and (on embedded) that **interrupts are disabled**. +/// +/// It is safe to use other logging functions while this function runs +/// (including all logging macros). +/// +/// [`set_logger`]: fn.set_logger.html +pub unsafe fn set_logger_racy(logger: &'static dyn Log) -> Result<(), SetLoggerError> { + match STATE.load(Ordering::Acquire) { + UNINITIALIZED => { + LOGGER = logger; + STATE.store(INITIALIZED, Ordering::Release); + Ok(()) + } + INITIALIZING => { + // This is just plain UB, since we were racing another initialization function + unreachable!("set_logger_racy must not be used with other initialization functions") + } + _ => Err(SetLoggerError(())), + } +} + +/// The type returned by [`set_logger`] if [`set_logger`] has already been called. +/// +/// [`set_logger`]: fn.set_logger.html +#[allow(missing_copy_implementations)] +#[derive(Debug)] +pub struct SetLoggerError(()); + +impl fmt::Display for SetLoggerError { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.write_str(SET_LOGGER_ERROR) + } +} + +// The Error trait is not available in libcore +#[cfg(feature = "std")] +impl error::Error for SetLoggerError {} + +/// The type returned by [`from_str`] when the string doesn't match any of the log levels. +/// +/// [`from_str`]: https://doc.rust-lang.org/std/str/trait.FromStr.html#tymethod.from_str +#[allow(missing_copy_implementations)] +#[derive(Debug, PartialEq, Eq)] +pub struct ParseLevelError(()); + +impl fmt::Display for ParseLevelError { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.write_str(LEVEL_PARSE_ERROR) + } +} + +// The Error trait is not available in libcore +#[cfg(feature = "std")] +impl error::Error for ParseLevelError {} + +/// Returns a reference to the logger. +/// +/// If a logger has not been set, a no-op implementation is returned. +pub fn logger() -> &'static dyn Log { + // Acquire memory ordering guarantees that current thread would see any + // memory writes that happened before store of the value + // into `STATE` with memory ordering `Release` or stronger. + // + // Since the value `INITIALIZED` is written only after `LOGGER` was + // initialized, observing it after `Acquire` load here makes both + // write to the `LOGGER` static and initialization of the logger + // internal state synchronized with current thread. + if STATE.load(Ordering::Acquire) != INITIALIZED { + static NOP: NopLogger = NopLogger; + &NOP + } else { + unsafe { LOGGER } + } +} + +// WARNING: this is not part of the crate's public API and is subject to change at any time +#[doc(hidden)] +pub mod __private_api; + +/// The statically resolved maximum log level. +/// +/// See the crate level documentation for information on how to configure this. +/// +/// This value is checked by the log macros, but not by the `Log`ger returned by +/// the [`logger`] function. Code that manually calls functions on that value +/// should compare the level against this value. +/// +/// [`logger`]: fn.logger.html +pub const STATIC_MAX_LEVEL: LevelFilter = match cfg!(debug_assertions) { + false if cfg!(feature = "release_max_level_off") => LevelFilter::Off, + false if cfg!(feature = "release_max_level_error") => LevelFilter::Error, + false if cfg!(feature = "release_max_level_warn") => LevelFilter::Warn, + false if cfg!(feature = "release_max_level_info") => LevelFilter::Info, + false if cfg!(feature = "release_max_level_debug") => LevelFilter::Debug, + false if cfg!(feature = "release_max_level_trace") => LevelFilter::Trace, + _ if cfg!(feature = "max_level_off") => LevelFilter::Off, + _ if cfg!(feature = "max_level_error") => LevelFilter::Error, + _ if cfg!(feature = "max_level_warn") => LevelFilter::Warn, + _ if cfg!(feature = "max_level_info") => LevelFilter::Info, + _ if cfg!(feature = "max_level_debug") => LevelFilter::Debug, + _ => LevelFilter::Trace, +}; + +#[cfg(test)] +mod tests { + use super::{Level, LevelFilter, ParseLevelError, STATIC_MAX_LEVEL}; + + #[test] + fn test_levelfilter_from_str() { + let tests = [ + ("off", Ok(LevelFilter::Off)), + ("error", Ok(LevelFilter::Error)), + ("warn", Ok(LevelFilter::Warn)), + ("info", Ok(LevelFilter::Info)), + ("debug", Ok(LevelFilter::Debug)), + ("trace", Ok(LevelFilter::Trace)), + ("OFF", Ok(LevelFilter::Off)), + ("ERROR", Ok(LevelFilter::Error)), + ("WARN", Ok(LevelFilter::Warn)), + ("INFO", Ok(LevelFilter::Info)), + ("DEBUG", Ok(LevelFilter::Debug)), + ("TRACE", Ok(LevelFilter::Trace)), + ("asdf", Err(ParseLevelError(()))), + ]; + for &(s, ref expected) in &tests { + assert_eq!(expected, &s.parse()); + } + } + + #[test] + fn test_level_from_str() { + let tests = [ + ("OFF", Err(ParseLevelError(()))), + ("error", Ok(Level::Error)), + ("warn", Ok(Level::Warn)), + ("info", Ok(Level::Info)), + ("debug", Ok(Level::Debug)), + ("trace", Ok(Level::Trace)), + ("ERROR", Ok(Level::Error)), + ("WARN", Ok(Level::Warn)), + ("INFO", Ok(Level::Info)), + ("DEBUG", Ok(Level::Debug)), + ("TRACE", Ok(Level::Trace)), + ("asdf", Err(ParseLevelError(()))), + ]; + for &(s, ref expected) in &tests { + assert_eq!(expected, &s.parse()); + } + } + + #[test] + fn test_level_as_str() { + let tests = &[ + (Level::Error, "ERROR"), + (Level::Warn, "WARN"), + (Level::Info, "INFO"), + (Level::Debug, "DEBUG"), + (Level::Trace, "TRACE"), + ]; + for (input, expected) in tests { + assert_eq!(*expected, input.as_str()); + } + } + + #[test] + fn test_level_show() { + assert_eq!("INFO", Level::Info.to_string()); + assert_eq!("ERROR", Level::Error.to_string()); + } + + #[test] + fn test_levelfilter_show() { + assert_eq!("OFF", LevelFilter::Off.to_string()); + assert_eq!("ERROR", LevelFilter::Error.to_string()); + } + + #[test] + fn test_cross_cmp() { + assert!(Level::Debug > LevelFilter::Error); + assert!(LevelFilter::Warn < Level::Trace); + assert!(LevelFilter::Off < Level::Error); + } + + #[test] + fn test_cross_eq() { + assert!(Level::Error == LevelFilter::Error); + assert!(LevelFilter::Off != Level::Error); + assert!(Level::Trace == LevelFilter::Trace); + } + + #[test] + fn test_to_level() { + assert_eq!(Some(Level::Error), LevelFilter::Error.to_level()); + assert_eq!(None, LevelFilter::Off.to_level()); + assert_eq!(Some(Level::Debug), LevelFilter::Debug.to_level()); + } + + #[test] + fn test_to_level_filter() { + assert_eq!(LevelFilter::Error, Level::Error.to_level_filter()); + assert_eq!(LevelFilter::Trace, Level::Trace.to_level_filter()); + } + + #[test] + fn test_level_filter_as_str() { + let tests = &[ + (LevelFilter::Off, "OFF"), + (LevelFilter::Error, "ERROR"), + (LevelFilter::Warn, "WARN"), + (LevelFilter::Info, "INFO"), + (LevelFilter::Debug, "DEBUG"), + (LevelFilter::Trace, "TRACE"), + ]; + for (input, expected) in tests { + assert_eq!(*expected, input.as_str()); + } + } + + #[test] + #[cfg_attr(not(debug_assertions), ignore)] + fn test_static_max_level_debug() { + if cfg!(feature = "max_level_off") { + assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Off); + } else if cfg!(feature = "max_level_error") { + assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Error); + } else if cfg!(feature = "max_level_warn") { + assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Warn); + } else if cfg!(feature = "max_level_info") { + assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Info); + } else if cfg!(feature = "max_level_debug") { + assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Debug); + } else { + assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Trace); + } + } + + #[test] + #[cfg_attr(debug_assertions, ignore)] + fn test_static_max_level_release() { + if cfg!(feature = "release_max_level_off") { + assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Off); + } else if cfg!(feature = "release_max_level_error") { + assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Error); + } else if cfg!(feature = "release_max_level_warn") { + assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Warn); + } else if cfg!(feature = "release_max_level_info") { + assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Info); + } else if cfg!(feature = "release_max_level_debug") { + assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Debug); + } else if cfg!(feature = "release_max_level_trace") { + assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Trace); + } else if cfg!(feature = "max_level_off") { + assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Off); + } else if cfg!(feature = "max_level_error") { + assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Error); + } else if cfg!(feature = "max_level_warn") { + assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Warn); + } else if cfg!(feature = "max_level_info") { + assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Info); + } else if cfg!(feature = "max_level_debug") { + assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Debug); + } else { + assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Trace); + } + } + + #[test] + #[cfg(feature = "std")] + fn test_error_trait() { + use super::SetLoggerError; + let e = SetLoggerError(()); + assert_eq!( + &e.to_string(), + "attempted to set a logger after the logging system \ + was already initialized" + ); + } + + #[test] + fn test_metadata_builder() { + use super::MetadataBuilder; + let target = "myApp"; + let metadata_test = MetadataBuilder::new() + .level(Level::Debug) + .target(target) + .build(); + assert_eq!(metadata_test.level(), Level::Debug); + assert_eq!(metadata_test.target(), "myApp"); + } + + #[test] + fn test_metadata_convenience_builder() { + use super::Metadata; + let target = "myApp"; + let metadata_test = Metadata::builder() + .level(Level::Debug) + .target(target) + .build(); + assert_eq!(metadata_test.level(), Level::Debug); + assert_eq!(metadata_test.target(), "myApp"); + } + + #[test] + fn test_record_builder() { + use super::{MetadataBuilder, RecordBuilder}; + let target = "myApp"; + let metadata = MetadataBuilder::new().target(target).build(); + let fmt_args = format_args!("hello"); + let record_test = RecordBuilder::new() + .args(fmt_args) + .metadata(metadata) + .module_path(Some("foo")) + .file(Some("bar")) + .line(Some(30)) + .build(); + assert_eq!(record_test.metadata().target(), "myApp"); + assert_eq!(record_test.module_path(), Some("foo")); + assert_eq!(record_test.file(), Some("bar")); + assert_eq!(record_test.line(), Some(30)); + } + + #[test] + fn test_record_convenience_builder() { + use super::{Metadata, Record}; + let target = "myApp"; + let metadata = Metadata::builder().target(target).build(); + let fmt_args = format_args!("hello"); + let record_test = Record::builder() + .args(fmt_args) + .metadata(metadata) + .module_path(Some("foo")) + .file(Some("bar")) + .line(Some(30)) + .build(); + assert_eq!(record_test.target(), "myApp"); + assert_eq!(record_test.module_path(), Some("foo")); + assert_eq!(record_test.file(), Some("bar")); + assert_eq!(record_test.line(), Some(30)); + } + + #[test] + fn test_record_complete_builder() { + use super::{Level, Record}; + let target = "myApp"; + let record_test = Record::builder() + .module_path(Some("foo")) + .file(Some("bar")) + .line(Some(30)) + .target(target) + .level(Level::Error) + .build(); + assert_eq!(record_test.target(), "myApp"); + assert_eq!(record_test.level(), Level::Error); + assert_eq!(record_test.module_path(), Some("foo")); + assert_eq!(record_test.file(), Some("bar")); + assert_eq!(record_test.line(), Some(30)); + } + + #[test] + #[cfg(feature = "kv")] + fn test_record_key_values_builder() { + use super::Record; + use crate::kv::{self, VisitSource}; + + struct TestVisitSource { + seen_pairs: usize, + } + + impl<'kvs> VisitSource<'kvs> for TestVisitSource { + fn visit_pair( + &mut self, + _: kv::Key<'kvs>, + _: kv::Value<'kvs>, + ) -> Result<(), kv::Error> { + self.seen_pairs += 1; + Ok(()) + } + } + + let kvs: &[(&str, i32)] = &[("a", 1), ("b", 2)]; + let record_test = Record::builder().key_values(&kvs).build(); + + let mut visitor = TestVisitSource { seen_pairs: 0 }; + + record_test.key_values().visit(&mut visitor).unwrap(); + + assert_eq!(2, visitor.seen_pairs); + } + + #[test] + #[cfg(feature = "kv")] + fn test_record_key_values_get_coerce() { + use super::Record; + + let kvs: &[(&str, &str)] = &[("a", "1"), ("b", "2")]; + let record = Record::builder().key_values(&kvs).build(); + + assert_eq!( + "2", + record + .key_values() + .get("b".into()) + .expect("missing key") + .to_borrowed_str() + .expect("invalid value") + ); + } + + // Test that the `impl Log for Foo` blocks work + // This test mostly operates on a type level, so failures will be compile errors + #[test] + fn test_foreign_impl() { + use super::Log; + #[cfg(feature = "std")] + use std::sync::Arc; + + fn assert_is_log<T: Log + ?Sized>() {} + + assert_is_log::<&dyn Log>(); + + #[cfg(feature = "std")] + assert_is_log::<Box<dyn Log>>(); + + #[cfg(feature = "std")] + assert_is_log::<Arc<dyn Log>>(); + + // Assert these statements for all T: Log + ?Sized + #[allow(unused)] + fn forall<T: Log + ?Sized>() { + #[cfg(feature = "std")] + assert_is_log::<Box<T>>(); + + assert_is_log::<&T>(); + + #[cfg(feature = "std")] + assert_is_log::<Arc<T>>(); + } + } +} diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/macros.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/macros.rs new file mode 100644 index 0000000..87693f2 --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/macros.rs @@ -0,0 +1,367 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/// The standard logging macro. +/// +/// This macro will generically log with the specified `Level` and `format!` +/// based argument list. +/// +/// # Examples +/// +/// ``` +/// use log::{log, Level}; +/// +/// # fn main() { +/// let data = (42, "Forty-two"); +/// let private_data = "private"; +/// +/// log!(Level::Error, "Received errors: {}, {}", data.0, data.1); +/// log!(target: "app_events", Level::Warn, "App warning: {}, {}, {}", +/// data.0, data.1, private_data); +/// # } +/// ``` +#[macro_export] +macro_rules! log { + // log!(target: "my_target", Level::Info, key1:? = 42, key2 = true; "a {} event", "log"); + (target: $target:expr, $lvl:expr, $($key:tt $(:$capture:tt)? $(= $value:expr)?),+; $($arg:tt)+) => ({ + let lvl = $lvl; + if lvl <= $crate::STATIC_MAX_LEVEL && lvl <= $crate::max_level() { + $crate::__private_api::log::<&_>( + $crate::__private_api::format_args!($($arg)+), + lvl, + &($target, $crate::__private_api::module_path!(), $crate::__private_api::loc()), + &[$(($crate::__log_key!($key), $crate::__log_value!($key $(:$capture)* = $($value)*))),+] + ); + } + }); + + // log!(target: "my_target", Level::Info, "a {} event", "log"); + (target: $target:expr, $lvl:expr, $($arg:tt)+) => ({ + let lvl = $lvl; + if lvl <= $crate::STATIC_MAX_LEVEL && lvl <= $crate::max_level() { + $crate::__private_api::log( + $crate::__private_api::format_args!($($arg)+), + lvl, + &($target, $crate::__private_api::module_path!(), $crate::__private_api::loc()), + (), + ); + } + }); + + // log!(Level::Info, "a log event") + ($lvl:expr, $($arg:tt)+) => ($crate::log!(target: $crate::__private_api::module_path!(), $lvl, $($arg)+)); +} + +/// Logs a message at the error level. +/// +/// # Examples +/// +/// ``` +/// use log::error; +/// +/// # fn main() { +/// let (err_info, port) = ("No connection", 22); +/// +/// error!("Error: {err_info} on port {port}"); +/// error!(target: "app_events", "App Error: {err_info}, Port: {port}"); +/// # } +/// ``` +#[macro_export] +macro_rules! error { + // error!(target: "my_target", key1 = 42, key2 = true; "a {} event", "log") + // error!(target: "my_target", "a {} event", "log") + (target: $target:expr, $($arg:tt)+) => ($crate::log!(target: $target, $crate::Level::Error, $($arg)+)); + + // error!("a {} event", "log") + ($($arg:tt)+) => ($crate::log!($crate::Level::Error, $($arg)+)) +} + +/// Logs a message at the warn level. +/// +/// # Examples +/// +/// ``` +/// use log::warn; +/// +/// # fn main() { +/// let warn_description = "Invalid Input"; +/// +/// warn!("Warning! {warn_description}!"); +/// warn!(target: "input_events", "App received warning: {warn_description}"); +/// # } +/// ``` +#[macro_export] +macro_rules! warn { + // warn!(target: "my_target", key1 = 42, key2 = true; "a {} event", "log") + // warn!(target: "my_target", "a {} event", "log") + (target: $target:expr, $($arg:tt)+) => ($crate::log!(target: $target, $crate::Level::Warn, $($arg)+)); + + // warn!("a {} event", "log") + ($($arg:tt)+) => ($crate::log!($crate::Level::Warn, $($arg)+)) +} + +/// Logs a message at the info level. +/// +/// # Examples +/// +/// ``` +/// use log::info; +/// +/// # fn main() { +/// # struct Connection { port: u32, speed: f32 } +/// let conn_info = Connection { port: 40, speed: 3.20 }; +/// +/// info!("Connected to port {} at {} Mb/s", conn_info.port, conn_info.speed); +/// info!(target: "connection_events", "Successful connection, port: {}, speed: {}", +/// conn_info.port, conn_info.speed); +/// # } +/// ``` +#[macro_export] +macro_rules! info { + // info!(target: "my_target", key1 = 42, key2 = true; "a {} event", "log") + // info!(target: "my_target", "a {} event", "log") + (target: $target:expr, $($arg:tt)+) => ($crate::log!(target: $target, $crate::Level::Info, $($arg)+)); + + // info!("a {} event", "log") + ($($arg:tt)+) => ($crate::log!($crate::Level::Info, $($arg)+)) +} + +/// Logs a message at the debug level. +/// +/// # Examples +/// +/// ``` +/// use log::debug; +/// +/// # fn main() { +/// # struct Position { x: f32, y: f32 } +/// let pos = Position { x: 3.234, y: -1.223 }; +/// +/// debug!("New position: x: {}, y: {}", pos.x, pos.y); +/// debug!(target: "app_events", "New position: x: {}, y: {}", pos.x, pos.y); +/// # } +/// ``` +#[macro_export] +macro_rules! debug { + // debug!(target: "my_target", key1 = 42, key2 = true; "a {} event", "log") + // debug!(target: "my_target", "a {} event", "log") + (target: $target:expr, $($arg:tt)+) => ($crate::log!(target: $target, $crate::Level::Debug, $($arg)+)); + + // debug!("a {} event", "log") + ($($arg:tt)+) => ($crate::log!($crate::Level::Debug, $($arg)+)) +} + +/// Logs a message at the trace level. +/// +/// # Examples +/// +/// ``` +/// use log::trace; +/// +/// # fn main() { +/// # struct Position { x: f32, y: f32 } +/// let pos = Position { x: 3.234, y: -1.223 }; +/// +/// trace!("Position is: x: {}, y: {}", pos.x, pos.y); +/// trace!(target: "app_events", "x is {} and y is {}", +/// if pos.x >= 0.0 { "positive" } else { "negative" }, +/// if pos.y >= 0.0 { "positive" } else { "negative" }); +/// # } +/// ``` +#[macro_export] +macro_rules! trace { + // trace!(target: "my_target", key1 = 42, key2 = true; "a {} event", "log") + // trace!(target: "my_target", "a {} event", "log") + (target: $target:expr, $($arg:tt)+) => ($crate::log!(target: $target, $crate::Level::Trace, $($arg)+)); + + // trace!("a {} event", "log") + ($($arg:tt)+) => ($crate::log!($crate::Level::Trace, $($arg)+)) +} + +/// Determines if a message logged at the specified level in that module will +/// be logged. +/// +/// This can be used to avoid expensive computation of log message arguments if +/// the message would be ignored anyway. +/// +/// # Examples +/// +/// ``` +/// use log::Level::Debug; +/// use log::{debug, log_enabled}; +/// +/// # fn foo() { +/// if log_enabled!(Debug) { +/// let data = expensive_call(); +/// debug!("expensive debug data: {} {}", data.x, data.y); +/// } +/// if log_enabled!(target: "Global", Debug) { +/// let data = expensive_call(); +/// debug!(target: "Global", "expensive debug data: {} {}", data.x, data.y); +/// } +/// # } +/// # struct Data { x: u32, y: u32 } +/// # fn expensive_call() -> Data { Data { x: 0, y: 0 } } +/// # fn main() {} +/// ``` +#[macro_export] +macro_rules! log_enabled { + (target: $target:expr, $lvl:expr) => {{ + let lvl = $lvl; + lvl <= $crate::STATIC_MAX_LEVEL + && lvl <= $crate::max_level() + && $crate::__private_api::enabled(lvl, $target) + }}; + ($lvl:expr) => { + $crate::log_enabled!(target: $crate::__private_api::module_path!(), $lvl) + }; +} + +// These macros use a pattern of #[cfg]s to produce nicer error +// messages when log features aren't available + +#[doc(hidden)] +#[macro_export] +#[cfg(feature = "kv")] +macro_rules! __log_key { + // key1 = 42 + ($($args:ident)*) => { + $crate::__private_api::stringify!($($args)*) + }; + // "key1" = 42 + ($($args:expr)*) => { + $($args)* + }; +} + +#[doc(hidden)] +#[macro_export] +#[cfg(not(feature = "kv"))] +macro_rules! __log_key { + ($($args:tt)*) => { + compile_error!("key value support requires the `kv` feature of `log`") + }; +} + +#[doc(hidden)] +#[macro_export] +#[cfg(feature = "kv")] +macro_rules! __log_value { + // Entrypoint + ($key:tt = $args:expr) => { + $crate::__log_value!(($args):value) + }; + ($key:tt :$capture:tt = $args:expr) => { + $crate::__log_value!(($args):$capture) + }; + ($key:ident =) => { + $crate::__log_value!(($key):value) + }; + ($key:ident :$capture:tt =) => { + $crate::__log_value!(($key):$capture) + }; + // ToValue + (($args:expr):value) => { + $crate::__private_api::capture_to_value(&&$args) + }; + // Debug + (($args:expr):?) => { + $crate::__private_api::capture_debug(&&$args) + }; + (($args:expr):debug) => { + $crate::__private_api::capture_debug(&&$args) + }; + // Display + (($args:expr):%) => { + $crate::__private_api::capture_display(&&$args) + }; + (($args:expr):display) => { + $crate::__private_api::capture_display(&&$args) + }; + //Error + (($args:expr):err) => { + $crate::__log_value_error!($args) + }; + // sval::Value + (($args:expr):sval) => { + $crate::__log_value_sval!($args) + }; + // serde::Serialize + (($args:expr):serde) => { + $crate::__log_value_serde!($args) + }; +} + +#[doc(hidden)] +#[macro_export] +#[cfg(not(feature = "kv"))] +macro_rules! __log_value { + ($($args:tt)*) => { + compile_error!("key value support requires the `kv` feature of `log`") + }; +} + +#[doc(hidden)] +#[macro_export] +#[cfg(feature = "kv_sval")] +macro_rules! __log_value_sval { + ($args:expr) => { + $crate::__private_api::capture_sval(&&$args) + }; +} + +#[doc(hidden)] +#[macro_export] +#[cfg(not(feature = "kv_sval"))] +macro_rules! __log_value_sval { + ($args:expr) => { + compile_error!("capturing values as `sval::Value` requites the `kv_sval` feature of `log`") + }; +} + +#[doc(hidden)] +#[macro_export] +#[cfg(feature = "kv_serde")] +macro_rules! __log_value_serde { + ($args:expr) => { + $crate::__private_api::capture_serde(&&$args) + }; +} + +#[doc(hidden)] +#[macro_export] +#[cfg(not(feature = "kv_serde"))] +macro_rules! __log_value_serde { + ($args:expr) => { + compile_error!( + "capturing values as `serde::Serialize` requites the `kv_serde` feature of `log`" + ) + }; +} + +#[doc(hidden)] +#[macro_export] +#[cfg(feature = "kv_std")] +macro_rules! __log_value_error { + ($args:expr) => { + $crate::__private_api::capture_error(&$args) + }; +} + +#[doc(hidden)] +#[macro_export] +#[cfg(not(feature = "kv_std"))] +macro_rules! __log_value_error { + ($args:expr) => { + compile_error!( + "capturing values as `std::error::Error` requites the `kv_std` feature of `log`" + ) + }; +} diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/serde.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/serde.rs new file mode 100644 index 0000000..63bef7f --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/serde.rs @@ -0,0 +1,397 @@ +#![cfg(feature = "serde")] + +use serde::de::{ + Deserialize, DeserializeSeed, Deserializer, EnumAccess, Error, Unexpected, VariantAccess, + Visitor, +}; +use serde::ser::{Serialize, Serializer}; + +use crate::{Level, LevelFilter, LOG_LEVEL_NAMES}; + +use std::fmt; +use std::str::{self, FromStr}; + +// The Deserialize impls are handwritten to be case insensitive using FromStr. + +impl Serialize for Level { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + match *self { + Level::Error => serializer.serialize_unit_variant("Level", 0, "ERROR"), + Level::Warn => serializer.serialize_unit_variant("Level", 1, "WARN"), + Level::Info => serializer.serialize_unit_variant("Level", 2, "INFO"), + Level::Debug => serializer.serialize_unit_variant("Level", 3, "DEBUG"), + Level::Trace => serializer.serialize_unit_variant("Level", 4, "TRACE"), + } + } +} + +impl<'de> Deserialize<'de> for Level { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + struct LevelIdentifier; + + impl<'de> Visitor<'de> for LevelIdentifier { + type Value = Level; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("log level") + } + + fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E> + where + E: Error, + { + let variant = LOG_LEVEL_NAMES[1..] + .get(v as usize) + .ok_or_else(|| Error::invalid_value(Unexpected::Unsigned(v), &self))?; + + self.visit_str(variant) + } + + fn visit_str<E>(self, s: &str) -> Result<Self::Value, E> + where + E: Error, + { + // Case insensitive. + FromStr::from_str(s).map_err(|_| Error::unknown_variant(s, &LOG_LEVEL_NAMES[1..])) + } + + fn visit_bytes<E>(self, value: &[u8]) -> Result<Self::Value, E> + where + E: Error, + { + let variant = str::from_utf8(value) + .map_err(|_| Error::invalid_value(Unexpected::Bytes(value), &self))?; + + self.visit_str(variant) + } + } + + impl<'de> DeserializeSeed<'de> for LevelIdentifier { + type Value = Level; + + fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error> + where + D: Deserializer<'de>, + { + deserializer.deserialize_identifier(LevelIdentifier) + } + } + + struct LevelEnum; + + impl<'de> Visitor<'de> for LevelEnum { + type Value = Level; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("log level") + } + + fn visit_enum<A>(self, value: A) -> Result<Self::Value, A::Error> + where + A: EnumAccess<'de>, + { + let (level, variant) = value.variant_seed(LevelIdentifier)?; + // Every variant is a unit variant. + variant.unit_variant()?; + Ok(level) + } + } + + deserializer.deserialize_enum("Level", &LOG_LEVEL_NAMES[1..], LevelEnum) + } +} + +impl Serialize for LevelFilter { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + match *self { + LevelFilter::Off => serializer.serialize_unit_variant("LevelFilter", 0, "OFF"), + LevelFilter::Error => serializer.serialize_unit_variant("LevelFilter", 1, "ERROR"), + LevelFilter::Warn => serializer.serialize_unit_variant("LevelFilter", 2, "WARN"), + LevelFilter::Info => serializer.serialize_unit_variant("LevelFilter", 3, "INFO"), + LevelFilter::Debug => serializer.serialize_unit_variant("LevelFilter", 4, "DEBUG"), + LevelFilter::Trace => serializer.serialize_unit_variant("LevelFilter", 5, "TRACE"), + } + } +} + +impl<'de> Deserialize<'de> for LevelFilter { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + struct LevelFilterIdentifier; + + impl<'de> Visitor<'de> for LevelFilterIdentifier { + type Value = LevelFilter; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("log level filter") + } + + fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E> + where + E: Error, + { + let variant = LOG_LEVEL_NAMES + .get(v as usize) + .ok_or_else(|| Error::invalid_value(Unexpected::Unsigned(v), &self))?; + + self.visit_str(variant) + } + + fn visit_str<E>(self, s: &str) -> Result<Self::Value, E> + where + E: Error, + { + // Case insensitive. + FromStr::from_str(s).map_err(|_| Error::unknown_variant(s, &LOG_LEVEL_NAMES)) + } + + fn visit_bytes<E>(self, value: &[u8]) -> Result<Self::Value, E> + where + E: Error, + { + let variant = str::from_utf8(value) + .map_err(|_| Error::invalid_value(Unexpected::Bytes(value), &self))?; + + self.visit_str(variant) + } + } + + impl<'de> DeserializeSeed<'de> for LevelFilterIdentifier { + type Value = LevelFilter; + + fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error> + where + D: Deserializer<'de>, + { + deserializer.deserialize_identifier(LevelFilterIdentifier) + } + } + + struct LevelFilterEnum; + + impl<'de> Visitor<'de> for LevelFilterEnum { + type Value = LevelFilter; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("log level filter") + } + + fn visit_enum<A>(self, value: A) -> Result<Self::Value, A::Error> + where + A: EnumAccess<'de>, + { + let (level_filter, variant) = value.variant_seed(LevelFilterIdentifier)?; + // Every variant is a unit variant. + variant.unit_variant()?; + Ok(level_filter) + } + } + + deserializer.deserialize_enum("LevelFilter", &LOG_LEVEL_NAMES, LevelFilterEnum) + } +} + +#[cfg(test)] +mod tests { + use crate::{Level, LevelFilter}; + use serde_test::{assert_de_tokens, assert_de_tokens_error, assert_tokens, Token}; + + fn level_token(variant: &'static str) -> Token { + Token::UnitVariant { + name: "Level", + variant, + } + } + + fn level_bytes_tokens(variant: &'static [u8]) -> [Token; 3] { + [ + Token::Enum { name: "Level" }, + Token::Bytes(variant), + Token::Unit, + ] + } + + fn level_variant_tokens(variant: u32) -> [Token; 3] { + [ + Token::Enum { name: "Level" }, + Token::U32(variant), + Token::Unit, + ] + } + + fn level_filter_token(variant: &'static str) -> Token { + Token::UnitVariant { + name: "LevelFilter", + variant, + } + } + + fn level_filter_bytes_tokens(variant: &'static [u8]) -> [Token; 3] { + [ + Token::Enum { + name: "LevelFilter", + }, + Token::Bytes(variant), + Token::Unit, + ] + } + + fn level_filter_variant_tokens(variant: u32) -> [Token; 3] { + [ + Token::Enum { + name: "LevelFilter", + }, + Token::U32(variant), + Token::Unit, + ] + } + + #[test] + fn test_level_ser_de() { + let cases = &[ + (Level::Error, [level_token("ERROR")]), + (Level::Warn, [level_token("WARN")]), + (Level::Info, [level_token("INFO")]), + (Level::Debug, [level_token("DEBUG")]), + (Level::Trace, [level_token("TRACE")]), + ]; + + for (s, expected) in cases { + assert_tokens(s, expected); + } + } + + #[test] + fn test_level_case_insensitive() { + let cases = &[ + (Level::Error, [level_token("error")]), + (Level::Warn, [level_token("warn")]), + (Level::Info, [level_token("info")]), + (Level::Debug, [level_token("debug")]), + (Level::Trace, [level_token("trace")]), + ]; + + for (s, expected) in cases { + assert_de_tokens(s, expected); + } + } + + #[test] + fn test_level_de_bytes() { + let cases = &[ + (Level::Error, level_bytes_tokens(b"ERROR")), + (Level::Warn, level_bytes_tokens(b"WARN")), + (Level::Info, level_bytes_tokens(b"INFO")), + (Level::Debug, level_bytes_tokens(b"DEBUG")), + (Level::Trace, level_bytes_tokens(b"TRACE")), + ]; + + for (value, tokens) in cases { + assert_de_tokens(value, tokens); + } + } + + #[test] + fn test_level_de_variant_index() { + let cases = &[ + (Level::Error, level_variant_tokens(0)), + (Level::Warn, level_variant_tokens(1)), + (Level::Info, level_variant_tokens(2)), + (Level::Debug, level_variant_tokens(3)), + (Level::Trace, level_variant_tokens(4)), + ]; + + for (value, tokens) in cases { + assert_de_tokens(value, tokens); + } + } + + #[test] + fn test_level_de_error() { + let msg = "unknown variant `errorx`, expected one of \ + `ERROR`, `WARN`, `INFO`, `DEBUG`, `TRACE`"; + assert_de_tokens_error::<Level>(&[level_token("errorx")], msg); + } + + #[test] + fn test_level_filter_ser_de() { + let cases = &[ + (LevelFilter::Off, [level_filter_token("OFF")]), + (LevelFilter::Error, [level_filter_token("ERROR")]), + (LevelFilter::Warn, [level_filter_token("WARN")]), + (LevelFilter::Info, [level_filter_token("INFO")]), + (LevelFilter::Debug, [level_filter_token("DEBUG")]), + (LevelFilter::Trace, [level_filter_token("TRACE")]), + ]; + + for (s, expected) in cases { + assert_tokens(s, expected); + } + } + + #[test] + fn test_level_filter_case_insensitive() { + let cases = &[ + (LevelFilter::Off, [level_filter_token("off")]), + (LevelFilter::Error, [level_filter_token("error")]), + (LevelFilter::Warn, [level_filter_token("warn")]), + (LevelFilter::Info, [level_filter_token("info")]), + (LevelFilter::Debug, [level_filter_token("debug")]), + (LevelFilter::Trace, [level_filter_token("trace")]), + ]; + + for (s, expected) in cases { + assert_de_tokens(s, expected); + } + } + + #[test] + fn test_level_filter_de_bytes() { + let cases = &[ + (LevelFilter::Off, level_filter_bytes_tokens(b"OFF")), + (LevelFilter::Error, level_filter_bytes_tokens(b"ERROR")), + (LevelFilter::Warn, level_filter_bytes_tokens(b"WARN")), + (LevelFilter::Info, level_filter_bytes_tokens(b"INFO")), + (LevelFilter::Debug, level_filter_bytes_tokens(b"DEBUG")), + (LevelFilter::Trace, level_filter_bytes_tokens(b"TRACE")), + ]; + + for (value, tokens) in cases { + assert_de_tokens(value, tokens); + } + } + + #[test] + fn test_level_filter_de_variant_index() { + let cases = &[ + (LevelFilter::Off, level_filter_variant_tokens(0)), + (LevelFilter::Error, level_filter_variant_tokens(1)), + (LevelFilter::Warn, level_filter_variant_tokens(2)), + (LevelFilter::Info, level_filter_variant_tokens(3)), + (LevelFilter::Debug, level_filter_variant_tokens(4)), + (LevelFilter::Trace, level_filter_variant_tokens(5)), + ]; + + for (value, tokens) in cases { + assert_de_tokens(value, tokens); + } + } + + #[test] + fn test_level_filter_de_error() { + let msg = "unknown variant `errorx`, expected one of \ + `OFF`, `ERROR`, `WARN`, `INFO`, `DEBUG`, `TRACE`"; + assert_de_tokens_error::<LevelFilter>(&[level_filter_token("errorx")], msg); + } +} diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/triagebot.toml b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/triagebot.toml new file mode 100644 index 0000000..fa0824a --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/triagebot.toml @@ -0,0 +1 @@ +[assign] diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/.cargo-checksum.json b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/.cargo-checksum.json new file mode 100644 index 0000000..bcbce9e --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"d4ff1d54f23cde7d35174635e8db5e6aee0d61b846d2fccbf0d28146246b3a28","README.md":"fc6752d50a57acbf3d65581c0d2f3d0da8c5fef5735a12857660c9e9687751d0","src/facts.rs":"9fad471b6ba5f63b8a1367002fee2b27fc3b3b893680eca390bc2616718f8915","src/lib.rs":"19ef0fd2d054b3a48c11ff4007734b7940ca739d3a9d5083d3a03b4d982cdb99","src/output/datafrog_opt.rs":"c75fa04ed1cc1a5b59f9405ce959af5950d37ae57876cc9510adc7c013b25af5","src/output/initialization.rs":"b9665c1397ff5e1cc1a93e9645bec0bed672ea9822c4dd32fc545ecbd3f80258","src/output/liveness.rs":"b68c9edd17feebff7d0b006caaf8197b5c30320b1a8cdcbe653bd7218954dd4f","src/output/location_insensitive.rs":"eb7c495ec38768104b8877de66341aaca210cdad824cae948f3fd7cf4ba858d0","src/output/mod.rs":"968f8547954a4444f59f3c056a9b742aa59ede3a90bb9b6fe08ba506fcc6bce5","src/output/naive.rs":"b345c2beb8a2f79bc482d131954bea4f23e53a3ce8270f64b8e940f0de376730"},"package":"c4e8e505342045d397d0b6674dcb82d6faf5cf40484d30eeb88fc82ef14e903f"}
\ No newline at end of file diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/Cargo.toml b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/Cargo.toml new file mode 100644 index 0000000..e3a8f74 --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/Cargo.toml @@ -0,0 +1,29 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "polonius-engine" +version = "0.13.0" +authors = ["The Rust Project Developers", "Polonius Developers"] +description = "Core definition for the Rust borrow checker" +readme = "README.md" +keywords = ["compiler", "borrowck", "datalog"] +license = "Apache-2.0/MIT" +repository = "https://github.com/rust-lang-nursery/polonius" +[dependencies.datafrog] +version = "2.0.0" + +[dependencies.log] +version = "0.4" + +[dependencies.rustc-hash] +version = "1.0.0" diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/README.md b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/README.md new file mode 100644 index 0000000..d88295e --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/README.md @@ -0,0 +1,6 @@ +This is a core library that models the borrow check. It implements the +analysis [described in this blogpost][post]. This library is intended +for use both by rustc and by the polonius crate, which is a distinct +front-end intended for testing, profiling, etc. + +[post]: http://smallcultfollowing.com/babysteps/blog/2018/04/27/an-alias-based-formulation-of-the-borrow-checker/ diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/facts.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/facts.rs new file mode 100644 index 0000000..442ba18 --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/facts.rs @@ -0,0 +1,129 @@ +use std::fmt::Debug; +use std::hash::Hash; + +/// The "facts" which are the basis of the NLL borrow analysis. +#[derive(Clone, Debug)] +pub struct AllFacts<T: FactTypes> { + /// `loan_issued_at(origin, loan, point)` indicates that the `loan` was "issued" + /// at the given `point`, creating a reference with the `origin`. + /// Effectively, `origin` may refer to data from `loan` starting at `point` (this is usually + /// the point *after* a borrow rvalue). + pub loan_issued_at: Vec<(T::Origin, T::Loan, T::Point)>, + + /// `universal_region(origin)` -- this is a "free region" within fn body + pub universal_region: Vec<T::Origin>, + + /// `cfg_edge(point1, point2)` for each edge `point1 -> point2` in the control flow + pub cfg_edge: Vec<(T::Point, T::Point)>, + + /// `loan_killed_at(loan, point)` when some prefix of the path borrowed at `loan` + /// is assigned at `point`. + /// Indicates that the path borrowed by the `loan` has changed in some way that the loan no + /// longer needs to be tracked. (In particular, mutations to the path that was borrowed + /// no longer invalidate the loan) + pub loan_killed_at: Vec<(T::Loan, T::Point)>, + + /// `subset_base(origin1, origin2, point)` when we require `origin1@point: origin2@point`. + /// Indicates that `origin1 <= origin2` -- i.e., the set of loans in `origin1` are a subset + /// of those in `origin2`. + pub subset_base: Vec<(T::Origin, T::Origin, T::Point)>, + + /// `loan_invalidated_at(point, loan)` indicates that the `loan` is invalidated by some action + /// taking place at `point`; if any origin that references this loan is live, this is an error. + pub loan_invalidated_at: Vec<(T::Point, T::Loan)>, + + /// `var_used_at(var, point)` when the variable `var` is used for anything + /// but a drop at `point` + pub var_used_at: Vec<(T::Variable, T::Point)>, + + /// `var_defined_at(var, point)` when the variable `var` is overwritten at `point` + pub var_defined_at: Vec<(T::Variable, T::Point)>, + + /// `var_dropped_at(var, point)` when the variable `var` is used in a drop at `point` + pub var_dropped_at: Vec<(T::Variable, T::Point)>, + + /// `use_of_var_derefs_origin(variable, origin)`: References with the given + /// `origin` may be dereferenced when the `variable` is used. + /// + /// In rustc, we generate this whenever the type of the variable includes the + /// given origin. + pub use_of_var_derefs_origin: Vec<(T::Variable, T::Origin)>, + + /// `drop_of_var_derefs_origin(var, origin)` when the type of `var` includes + /// the `origin` and uses it when dropping + pub drop_of_var_derefs_origin: Vec<(T::Variable, T::Origin)>, + + /// `child_path(child, parent)` when the path `child` is the direct child of + /// `parent`, e.g. `child_path(x.y, x)`, but not `child_path(x.y.z, x)`. + pub child_path: Vec<(T::Path, T::Path)>, + + /// `path_is_var(path, var)` the root path `path` starting in variable `var`. + pub path_is_var: Vec<(T::Path, T::Variable)>, + + /// `path_assigned_at_base(path, point)` when the `path` was initialized at point + /// `point`. This fact is only emitted for a prefix `path`, and not for the + /// implicit initialization of all of `path`'s children. E.g. a statement like + /// `x.y = 3` at `point` would give the fact `path_assigned_at_base(x.y, point)` (but + /// neither `path_assigned_at_base(x.y.z, point)` nor `path_assigned_at_base(x, point)`). + pub path_assigned_at_base: Vec<(T::Path, T::Point)>, + + /// `path_moved_at_base(path, point)` when the `path` was moved at `point`. The + /// same logic is applied as for `path_assigned_at_base` above. + pub path_moved_at_base: Vec<(T::Path, T::Point)>, + + /// `path_accessed_at_base(path, point)` when the `path` was accessed at point + /// `point`. The same logic as for `path_assigned_at_base` and `path_moved_at_base` applies. + pub path_accessed_at_base: Vec<(T::Path, T::Point)>, + + /// These reflect the `'a: 'b` relations that are either declared by the user on function + /// declarations or which are inferred via implied bounds. + /// For example: `fn foo<'a, 'b: 'a, 'c>(x: &'c &'a u32)` would have two entries: + /// - one for the user-supplied subset `'b: 'a` + /// - and one for the `'a: 'c` implied bound from the `x` parameter, + /// (note that the transitive relation `'b: 'c` is not necessarily included + /// explicitly, but rather inferred by polonius). + pub known_placeholder_subset: Vec<(T::Origin, T::Origin)>, + + /// `placeholder(origin, loan)` describes a placeholder `origin`, with its associated + /// placeholder `loan`. + pub placeholder: Vec<(T::Origin, T::Loan)>, +} + +impl<T: FactTypes> Default for AllFacts<T> { + fn default() -> Self { + AllFacts { + loan_issued_at: Vec::default(), + universal_region: Vec::default(), + cfg_edge: Vec::default(), + loan_killed_at: Vec::default(), + subset_base: Vec::default(), + loan_invalidated_at: Vec::default(), + var_used_at: Vec::default(), + var_defined_at: Vec::default(), + var_dropped_at: Vec::default(), + use_of_var_derefs_origin: Vec::default(), + drop_of_var_derefs_origin: Vec::default(), + child_path: Vec::default(), + path_is_var: Vec::default(), + path_assigned_at_base: Vec::default(), + path_moved_at_base: Vec::default(), + path_accessed_at_base: Vec::default(), + known_placeholder_subset: Vec::default(), + placeholder: Vec::default(), + } + } +} + +pub trait Atom: + From<usize> + Into<usize> + Copy + Clone + Debug + Eq + Ord + Hash + 'static +{ + fn index(self) -> usize; +} + +pub trait FactTypes: Copy + Clone + Debug { + type Origin: Atom; + type Loan: Atom; + type Point: Atom; + type Variable: Atom; + type Path: Atom; +} diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/lib.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/lib.rs new file mode 100644 index 0000000..0926be8 --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/lib.rs @@ -0,0 +1,16 @@ +/// Contains the core of the Polonius borrow checking engine. +/// Input is fed in via AllFacts, and outputs are returned via Output +extern crate datafrog; +#[macro_use] +extern crate log; +extern crate rustc_hash; + +mod facts; +mod output; + +// Reexports of facts +pub use facts::AllFacts; +pub use facts::Atom; +pub use facts::FactTypes; +pub use output::Algorithm; +pub use output::Output; diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/output/datafrog_opt.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/output/datafrog_opt.rs new file mode 100644 index 0000000..da9c343 --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/output/datafrog_opt.rs @@ -0,0 +1,495 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use datafrog::{Iteration, Relation, RelationLeaper}; +use std::time::Instant; + +use crate::facts::FactTypes; +use crate::output::{Context, Output}; + +pub(super) fn compute<T: FactTypes>( + ctx: &Context<'_, T>, + result: &mut Output<T>, +) -> ( + Relation<(T::Loan, T::Point)>, + Relation<(T::Origin, T::Origin, T::Point)>, +) { + let timer = Instant::now(); + + let (errors, subset_errors) = { + // Static inputs + let origin_live_on_entry_rel = &ctx.origin_live_on_entry; + let cfg_edge_rel = &ctx.cfg_edge; + let loan_killed_at = &ctx.loan_killed_at; + let known_placeholder_subset = &ctx.known_placeholder_subset; + let placeholder_origin = &ctx.placeholder_origin; + + // Create a new iteration context, ... + let mut iteration = Iteration::new(); + + // `loan_invalidated_at` facts, stored ready for joins + let loan_invalidated_at = + iteration.variable::<((T::Loan, T::Point), ())>("loan_invalidated_at"); + + // we need `origin_live_on_entry` in both variable and relation forms, + // (respectively, for join and antijoin). + let origin_live_on_entry_var = + iteration.variable::<((T::Origin, T::Point), ())>("origin_live_on_entry"); + + // `loan_issued_at` input but organized for join + let loan_issued_at_op = + iteration.variable::<((T::Origin, T::Point), T::Loan)>("loan_issued_at_op"); + + // .decl subset(origin1, origin2, point) + // + // Indicates that `origin1: origin2` at `point`. + let subset_o1p = iteration.variable::<((T::Origin, T::Point), T::Origin)>("subset_o1p"); + + // .decl origin_contains_loan_on_entry(origin, loan, point) + // + // At `point`, things with `origin` may depend on data from `loan`. + let origin_contains_loan_on_entry_op = iteration + .variable::<((T::Origin, T::Point), T::Loan)>("origin_contains_loan_on_entry_op"); + + // .decl loan_live_at(loan, point) + // + // True if the restrictions of the `loan` need to be enforced at `point`. + let loan_live_at = iteration.variable::<((T::Loan, T::Point), ())>("loan_live_at"); + + // .decl live_to_dying_regions(origin1, origin2, point1, point2) + // + // The origins `origin1` and `origin2` are "live to dead" + // on the edge `point1 -> point2` if: + // + // - In `point1`, `origin1` <= `origin2` + // - In `point2`, `origin1` is live but `origin2` is dead. + // + // In that case, `point2` would like to add all the + // live things reachable from `origin2` to `origin1`. + // + let live_to_dying_regions_o2pq = iteration + .variable::<((T::Origin, T::Point, T::Point), T::Origin)>("live_to_dying_regions_o2pq"); + + // .decl dying_region_requires((origin, point1, point2), loan) + // + // The `origin` requires `loan`, but the `origin` goes dead + // along the edge `point1 -> point2`. + let dying_region_requires = iteration + .variable::<((T::Origin, T::Point, T::Point), T::Loan)>("dying_region_requires"); + + // .decl dying_can_reach_origins(origin, point1, point2) + // + // Contains dead origins where we are interested + // in computing the transitive closure of things they + // can reach. + // + // FIXME: this relation was named before renaming the `regions` atoms to `origins`, and + // will need to be renamed to change "_origins" to "_ascendants", "_roots", etc. + let dying_can_reach_origins = + iteration.variable::<((T::Origin, T::Point), T::Point)>("dying_can_reach_origins"); + + // .decl dying_can_reach(origin1, origin2, point1, point2) + // + // Indicates that `origin1`, which is dead + // in `point2`, can reach `origin2` in `point1`. + // + // This is effectively the transitive subset + // relation, but we try to limit it to origins + // that are dying on the edge `point1 -> point2`. + let dying_can_reach_o2q = + iteration.variable::<((T::Origin, T::Point), (T::Origin, T::Point))>("dying_can_reach"); + let dying_can_reach_1 = iteration.variable_indistinct("dying_can_reach_1"); + + // .decl dying_can_reach_live(origin1, origin2, point1, point2) + // + // Indicates that, along the edge `point1 -> point2`, the dead (in `point2`) + // `origin1` can reach the live (in `point2`) `origin2` via a subset + // relation. This is a subset of the full `dying_can_reach` + // relation where we filter down to those cases where `origin2` is + // live in `point2`. + let dying_can_reach_live = iteration + .variable::<((T::Origin, T::Point, T::Point), T::Origin)>("dying_can_reach_live"); + + // .decl dead_borrow_region_can_reach_root((origin, point), loan) + // + // Indicates a "borrow region" `origin` at `point` which is not live on + // entry to `point`. + let dead_borrow_region_can_reach_root = iteration + .variable::<((T::Origin, T::Point), T::Loan)>("dead_borrow_region_can_reach_root"); + + // .decl dead_borrow_region_can_reach_dead((origin2, point), loan) + let dead_borrow_region_can_reach_dead = iteration + .variable::<((T::Origin, T::Point), T::Loan)>("dead_borrow_region_can_reach_dead"); + let dead_borrow_region_can_reach_dead_1 = + iteration.variable_indistinct("dead_borrow_region_can_reach_dead_1"); + + // .decl errors(loan, point) + let errors = iteration.variable("errors"); + let subset_errors = iteration.variable::<(T::Origin, T::Origin, T::Point)>("subset_errors"); + + let subset_placeholder = + iteration.variable::<(T::Origin, T::Origin, T::Point)>("subset_placeholder"); + let subset_placeholder_o2p = iteration.variable_indistinct("subset_placeholder_o2p"); + + // Make "variable" versions of the relations, needed for joins. + loan_issued_at_op.extend( + ctx.loan_issued_at + .iter() + .map(|&(origin, loan, point)| ((origin, point), loan)), + ); + loan_invalidated_at.extend( + ctx.loan_invalidated_at + .iter() + .map(|&(loan, point)| ((loan, point), ())), + ); + origin_live_on_entry_var.extend( + origin_live_on_entry_rel + .iter() + .map(|&(origin, point)| ((origin, point), ())), + ); + + // subset(origin1, origin2, point) :- + // subset_base(origin1, origin2, point). + subset_o1p.extend( + ctx.subset_base + .iter() + .map(|&(origin1, origin2, point)| ((origin1, point), origin2)), + ); + + // origin_contains_loan_on_entry(origin, loan, point) :- + // loan_issued_at(origin, loan, point). + origin_contains_loan_on_entry_op.extend( + ctx.loan_issued_at + .iter() + .map(|&(origin, loan, point)| ((origin, point), loan)), + ); + + // .. and then start iterating rules! + while iteration.changed() { + // Cleanup step: remove symmetries + // - remove origins which are `subset`s of themselves + // + // FIXME: investigate whether is there a better way to do that without complicating + // the rules too much, because it would also require temporary variables and + // impact performance. Until then, the big reduction in tuples improves performance + // a lot, even if we're potentially adding a small number of tuples + // per round just to remove them in the next round. + subset_o1p + .recent + .borrow_mut() + .elements + .retain(|&((origin1, _), origin2)| origin1 != origin2); + + subset_placeholder + .recent + .borrow_mut() + .elements + .retain(|&(origin1, origin2, _)| origin1 != origin2); + subset_placeholder_o2p.from_map(&subset_placeholder, |&(origin1, origin2, point)| { + ((origin2, point), origin1) + }); + + // live_to_dying_regions(origin1, origin2, point1, point2) :- + // subset(origin1, origin2, point1), + // cfg_edge(point1, point2), + // origin_live_on_entry(origin1, point2), + // !origin_live_on_entry(origin2, point2). + live_to_dying_regions_o2pq.from_leapjoin( + &subset_o1p, + ( + cfg_edge_rel.extend_with(|&((_, point1), _)| point1), + origin_live_on_entry_rel.extend_with(|&((origin1, _), _)| origin1), + origin_live_on_entry_rel.extend_anti(|&((_, _), origin2)| origin2), + ), + |&((origin1, point1), origin2), &point2| ((origin2, point1, point2), origin1), + ); + + // dying_region_requires((origin, point1, point2), loan) :- + // origin_contains_loan_on_entry(origin, loan, point1), + // !loan_killed_at(loan, point1), + // cfg_edge(point1, point2), + // !origin_live_on_entry(origin, point2). + dying_region_requires.from_leapjoin( + &origin_contains_loan_on_entry_op, + ( + loan_killed_at.filter_anti(|&((_, point1), loan)| (loan, point1)), + cfg_edge_rel.extend_with(|&((_, point1), _)| point1), + origin_live_on_entry_rel.extend_anti(|&((origin, _), _)| origin), + ), + |&((origin, point1), loan), &point2| ((origin, point1, point2), loan), + ); + + // dying_can_reach_origins(origin2, point1, point2) :- + // live_to_dying_regions(_, origin2, point1, point2). + dying_can_reach_origins.from_map( + &live_to_dying_regions_o2pq, + |&((origin2, point1, point2), _origin1)| ((origin2, point1), point2), + ); + + // dying_can_reach_origins(origin, point1, point2) :- + // dying_region_requires(origin, point1, point2, _loan). + dying_can_reach_origins.from_map( + &dying_region_requires, + |&((origin, point1, point2), _loan)| ((origin, point1), point2), + ); + + // dying_can_reach(origin1, origin2, point1, point2) :- + // dying_can_reach_origins(origin1, point1, point2), + // subset(origin1, origin2, point1). + dying_can_reach_o2q.from_join( + &dying_can_reach_origins, + &subset_o1p, + |&(origin1, point1), &point2, &origin2| ((origin2, point2), (origin1, point1)), + ); + + // dying_can_reach(origin1, origin3, point1, point2) :- + // dying_can_reach(origin1, origin2, point1, point2), + // !origin_live_on_entry(origin2, point2), + // subset(origin2, origin3, point1). + // + // This is the "transitive closure" rule, but + // note that we only apply it with the + // "intermediate" `origin2` is dead at `point2`. + dying_can_reach_1.from_antijoin( + &dying_can_reach_o2q, + &origin_live_on_entry_rel, + |&(origin2, point2), &(origin1, point1)| ((origin2, point1), (origin1, point2)), + ); + dying_can_reach_o2q.from_join( + &dying_can_reach_1, + &subset_o1p, + |&(_origin2, point1), &(origin1, point2), &origin3| { + ((origin3, point2), (origin1, point1)) + }, + ); + + // dying_can_reach_live(origin1, origin2, point1, point2) :- + // dying_can_reach(origin1, origin2, point1, point2), + // origin_live_on_entry(origin2, point2). + dying_can_reach_live.from_join( + &dying_can_reach_o2q, + &origin_live_on_entry_var, + |&(origin2, point2), &(origin1, point1), _| ((origin1, point1, point2), origin2), + ); + + // subset(origin1, origin2, point2) :- + // subset(origin1, origin2, point1), + // cfg_edge(point1, point2), + // origin_live_on_entry(origin1, point2), + // origin_live_on_entry(origin2, point2). + // + // Carry `origin1 <= origin2` from `point1` into `point2` if both `origin1` and + // `origin2` are live in `point2`. + subset_o1p.from_leapjoin( + &subset_o1p, + ( + cfg_edge_rel.extend_with(|&((_, point1), _)| point1), + origin_live_on_entry_rel.extend_with(|&((origin1, _), _)| origin1), + origin_live_on_entry_rel.extend_with(|&((_, _), origin2)| origin2), + ), + |&((origin1, _point1), origin2), &point2| ((origin1, point2), origin2), + ); + + // subset(origin1, origin3, point2) :- + // live_to_dying_regions(origin1, origin2, point1, point2), + // dying_can_reach_live(origin2, origin3, point1, point2). + subset_o1p.from_join( + &live_to_dying_regions_o2pq, + &dying_can_reach_live, + |&(_origin2, _point1, point2), &origin1, &origin3| ((origin1, point2), origin3), + ); + + // origin_contains_loan_on_entry(origin2, loan, point2) :- + // dying_region_requires(origin1, loan, point1, point2), + // dying_can_reach_live(origin1, origin2, point1, point2). + // + // Communicate a `origin1 contains loan` relation across + // an edge `point1 -> point2` where `origin1` is dead in `point2`; in + // that case, for each origin `origin2` live in `point2` + // where `origin1 <= origin2` in `point1`, we add `origin2 contains loan` + // to `point2`. + origin_contains_loan_on_entry_op.from_join( + &dying_region_requires, + &dying_can_reach_live, + |&(_origin1, _point1, point2), &loan, &origin2| ((origin2, point2), loan), + ); + + // origin_contains_loan_on_entry(origin, loan, point2) :- + // origin_contains_loan_on_entry(origin, loan, point1), + // !loan_killed_at(loan, point1), + // cfg_edge(point1, point2), + // origin_live_on_entry(origin, point2). + origin_contains_loan_on_entry_op.from_leapjoin( + &origin_contains_loan_on_entry_op, + ( + loan_killed_at.filter_anti(|&((_, point1), loan)| (loan, point1)), + cfg_edge_rel.extend_with(|&((_, point1), _)| point1), + origin_live_on_entry_rel.extend_with(|&((origin, _), _)| origin), + ), + |&((origin, _), loan), &point2| ((origin, point2), loan), + ); + + // dead_borrow_region_can_reach_root((origin, point), loan) :- + // loan_issued_at(origin, loan, point), + // !origin_live_on_entry(origin, point). + dead_borrow_region_can_reach_root.from_antijoin( + &loan_issued_at_op, + &origin_live_on_entry_rel, + |&(origin, point), &loan| ((origin, point), loan), + ); + + // dead_borrow_region_can_reach_dead((origin, point), loan) :- + // dead_borrow_region_can_reach_root((origin, point), loan). + dead_borrow_region_can_reach_dead + .from_map(&dead_borrow_region_can_reach_root, |&tuple| tuple); + + // dead_borrow_region_can_reach_dead((origin2, point), loan) :- + // dead_borrow_region_can_reach_dead(origin1, loan, point), + // subset(origin1, origin2, point), + // !origin_live_on_entry(origin2, point). + dead_borrow_region_can_reach_dead_1.from_join( + &dead_borrow_region_can_reach_dead, + &subset_o1p, + |&(_origin1, point), &loan, &origin2| ((origin2, point), loan), + ); + dead_borrow_region_can_reach_dead.from_antijoin( + &dead_borrow_region_can_reach_dead_1, + &origin_live_on_entry_rel, + |&(origin2, point), &loan| ((origin2, point), loan), + ); + + // loan_live_at(loan, point) :- + // origin_contains_loan_on_entry(origin, loan, point), + // origin_live_on_entry(origin, point). + loan_live_at.from_join( + &origin_contains_loan_on_entry_op, + &origin_live_on_entry_var, + |&(_origin, point), &loan, _| ((loan, point), ()), + ); + + // loan_live_at(loan, point) :- + // dead_borrow_region_can_reach_dead(origin1, loan, point), + // subset(origin1, origin2, point), + // origin_live_on_entry(origin2, point). + // + // NB: the datafrog code below uses + // `dead_borrow_region_can_reach_dead_1`, which is equal + // to `dead_borrow_region_can_reach_dead` and `subset` + // joined together. + loan_live_at.from_join( + &dead_borrow_region_can_reach_dead_1, + &origin_live_on_entry_var, + |&(_origin2, point), &loan, _| ((loan, point), ()), + ); + + // errors(loan, point) :- + // loan_invalidated_at(loan, point), + // loan_live_at(loan, point). + errors.from_join( + &loan_invalidated_at, + &loan_live_at, + |&(loan, point), _, _| (loan, point), + ); + + // subset_placeholder(Origin1, Origin2, Point) :- + // subset(Origin1, Origin2, Point), + // placeholder_origin(Origin1). + subset_placeholder.from_leapjoin( + &subset_o1p, + ( + placeholder_origin.extend_with(|&((origin1, _point), _origin2)| origin1), + // remove symmetries: + datafrog::ValueFilter::from(|&((origin1, _point), origin2), _| { + origin1 != origin2 + }), + ), + |&((origin1, point), origin2), _| (origin1, origin2, point), + ); + + // We compute the transitive closure of the placeholder origins, so we + // maintain the invariant from the rule above that `Origin1` is a placeholder origin. + // + // subset_placeholder(Origin1, Origin3, Point) :- + // subset_placeholder(Origin1, Origin2, Point), + // subset(Origin2, Origin3, Point). + subset_placeholder.from_join( + &subset_placeholder_o2p, + &subset_o1p, + |&(_origin2, point), &origin1, &origin3| (origin1, origin3, point), + ); + + // subset_error(Origin1, Origin2, Point) :- + // subset_placeholder(Origin1, Origin2, Point), + // placeholder_origin(Origin2), + // !known_placeholder_subset(Origin1, Origin2). + subset_errors.from_leapjoin( + &subset_placeholder, + ( + placeholder_origin.extend_with(|&(_origin1, origin2, _point)| origin2), + known_placeholder_subset + .filter_anti(|&(origin1, origin2, _point)| (origin1, origin2)), + // remove symmetries: + datafrog::ValueFilter::from(|&(origin1, origin2, _point), _| { + origin1 != origin2 + }), + ), + |&(origin1, origin2, point), _| (origin1, origin2, point), + ); + } + + if result.dump_enabled { + let subset_o1p = subset_o1p.complete(); + assert!( + subset_o1p + .iter() + .filter(|&((origin1, _), origin2)| origin1 == origin2) + .count() + == 0, + "unwanted subset symmetries" + ); + for &((origin1, location), origin2) in subset_o1p.iter() { + result + .subset + .entry(location) + .or_default() + .entry(origin1) + .or_default() + .insert(origin2); + } + + let origin_contains_loan_on_entry_op = origin_contains_loan_on_entry_op.complete(); + for &((origin, location), loan) in origin_contains_loan_on_entry_op.iter() { + result + .origin_contains_loan_at + .entry(location) + .or_default() + .entry(origin) + .or_default() + .insert(loan); + } + + let loan_live_at = loan_live_at.complete(); + for &((loan, location), _) in loan_live_at.iter() { + result.loan_live_at.entry(location).or_default().push(loan); + } + } + + (errors.complete(), subset_errors.complete()) + }; + + info!( + "analysis done: {} `errors` tuples, {} `subset_errors` tuples, {:?}", + errors.len(), + subset_errors.len(), + timer.elapsed() + ); + + (errors, subset_errors) +} diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/output/initialization.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/output/initialization.rs new file mode 100644 index 0000000..30409d9 --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/output/initialization.rs @@ -0,0 +1,284 @@ +use std::time::Instant; + +use crate::facts::FactTypes; +use crate::output::{InitializationContext, Output}; + +use datafrog::{Iteration, Relation, RelationLeaper}; + +// This represents the output of an intermediate elaboration step (step 1). +struct TransitivePaths<T: FactTypes> { + path_moved_at: Relation<(T::Path, T::Point)>, + path_assigned_at: Relation<(T::Path, T::Point)>, + path_accessed_at: Relation<(T::Path, T::Point)>, + path_begins_with_var: Relation<(T::Path, T::Variable)>, +} + +struct InitializationStatus<T: FactTypes> { + var_maybe_partly_initialized_on_exit: Relation<(T::Variable, T::Point)>, + move_error: Relation<(T::Path, T::Point)>, +} + +pub(super) struct InitializationResult<T: FactTypes>( + pub(super) Relation<(T::Variable, T::Point)>, + pub(super) Relation<(T::Path, T::Point)>, +); + +// Step 1: compute transitive closures of path operations. This would elaborate, +// for example, an access to x into an access to x.f, x.f.0, etc. We do this for: +// - access to a path +// - initialization of a path +// - moves of a path +// FIXME: transitive rooting in a variable (path_begins_with_var) +// Note that this step may not be entirely necessary! +fn compute_transitive_paths<T: FactTypes>( + child_path: Vec<(T::Path, T::Path)>, + path_assigned_at_base: Vec<(T::Path, T::Point)>, + path_moved_at_base: Vec<(T::Path, T::Point)>, + path_accessed_at_base: Vec<(T::Path, T::Point)>, + path_is_var: Vec<(T::Path, T::Variable)>, +) -> TransitivePaths<T> { + let mut iteration = Iteration::new(); + let child_path: Relation<(T::Path, T::Path)> = child_path.into(); + + let ancestor_path = iteration.variable::<(T::Path, T::Path)>("ancestor"); + + // These are the actual targets: + let path_moved_at = iteration.variable::<(T::Path, T::Point)>("path_moved_at"); + let path_assigned_at = iteration.variable::<(T::Path, T::Point)>("path_initialized_at"); + let path_accessed_at = iteration.variable::<(T::Path, T::Point)>("path_accessed_at"); + let path_begins_with_var = iteration.variable::<(T::Path, T::Variable)>("path_begins_with_var"); + + // ancestor_path(Parent, Child) :- child_path(Child, Parent). + ancestor_path.extend(child_path.iter().map(|&(child, parent)| (parent, child))); + + // path_moved_at(Path, Point) :- path_moved_at_base(Path, Point). + path_moved_at.insert(path_moved_at_base.into()); + + // path_assigned_at(Path, Point) :- path_assigned_at_base(Path, Point). + path_assigned_at.insert(path_assigned_at_base.into()); + + // path_accessed_at(Path, Point) :- path_accessed_at_base(Path, Point). + path_accessed_at.insert(path_accessed_at_base.into()); + + // path_begins_with_var(Path, Var) :- path_is_var(Path, Var). + path_begins_with_var.insert(path_is_var.into()); + + while iteration.changed() { + // ancestor_path(Grandparent, Child) :- + // ancestor_path(Parent, Child), + // child_path(Parent, Grandparent). + ancestor_path.from_join( + &ancestor_path, + &child_path, + |&_parent, &child, &grandparent| (grandparent, child), + ); + + // moving a path moves its children + // path_moved_at(Child, Point) :- + // path_moved_at(Parent, Point), + // ancestor_path(Parent, Child). + path_moved_at.from_join(&path_moved_at, &ancestor_path, |&_parent, &p, &child| { + (child, p) + }); + + // initialising x at p initialises all x:s children + // path_assigned_at(Child, point) :- + // path_assigned_at(Parent, point), + // ancestor_path(Parent, Child). + path_assigned_at.from_join(&path_assigned_at, &ancestor_path, |&_parent, &p, &child| { + (child, p) + }); + + // accessing x at p accesses all x:s children at p (actually, + // accesses should be maximally precise and this shouldn't happen?) + // path_accessed_at(Child, point) :- + // path_accessed_at(Parent, point), + // ancestor_path(Parent, Child). + path_accessed_at.from_join(&path_accessed_at, &ancestor_path, |&_parent, &p, &child| { + (child, p) + }); + + // path_begins_with_var(Child, Var) :- + // path_begins_with_var(Parent, Var) + // ancestor_path(Parent, Child). + path_begins_with_var.from_join( + &path_begins_with_var, + &ancestor_path, + |&_parent, &var, &child| (child, var), + ); + } + + TransitivePaths { + path_assigned_at: path_assigned_at.complete(), + path_moved_at: path_moved_at.complete(), + path_accessed_at: path_accessed_at.complete(), + path_begins_with_var: path_begins_with_var.complete(), + } +} + +// Step 2: Compute path initialization and deinitialization across the CFG. +fn compute_move_errors<T: FactTypes>( + ctx: TransitivePaths<T>, + cfg_edge: &Relation<(T::Point, T::Point)>, + output: &mut Output<T>, +) -> InitializationStatus<T> { + let mut iteration = Iteration::new(); + // Variables + + // var_maybe_partly_initialized_on_exit(var, point): Upon leaving `point`, + // `var` is partially initialized for some path through the CFG, that is + // there has been an initialization of var, and var has not been moved in + // all paths through the CFG. + let var_maybe_partly_initialized_on_exit = + iteration.variable::<(T::Variable, T::Point)>("var_maybe_partly_initialized_on_exit"); + + // path_maybe_initialized_on_exit(path, point): Upon leaving `point`, the + // move path `path` is initialized for some path through the CFG. + let path_maybe_initialized_on_exit = + iteration.variable::<(T::Path, T::Point)>("path_maybe_initialized_on_exit"); + + // path_maybe_uninitialized_on_exit(Path, Point): There exists at least one + // path through the CFG to Point such that `Path` has been moved out by the + // time we arrive at `Point` without it being re-initialized for sure. + let path_maybe_uninitialized_on_exit = + iteration.variable::<(T::Path, T::Point)>("path_maybe_uninitialized_on_exit"); + + // move_error(Path, Point): There is an access to `Path` at `Point`, but + // `Path` is potentially moved (or never initialised). + let move_error = iteration.variable::<(T::Path, T::Point)>("move_error"); + + // Initial propagation of static relations + + // path_maybe_initialized_on_exit(path, point) :- path_assigned_at(path, point). + path_maybe_initialized_on_exit.insert(ctx.path_assigned_at.clone()); + + // path_maybe_uninitialized_on_exit(path, point) :- path_moved_at(path, point). + path_maybe_uninitialized_on_exit.insert(ctx.path_moved_at.clone()); + + while iteration.changed() { + // path_maybe_initialized_on_exit(path, point2) :- + // path_maybe_initialized_on_exit(path, point1), + // cfg_edge(point1, point2), + // !path_moved_at(path, point2). + path_maybe_initialized_on_exit.from_leapjoin( + &path_maybe_initialized_on_exit, + ( + cfg_edge.extend_with(|&(_path, point1)| point1), + ctx.path_moved_at.extend_anti(|&(path, _point1)| path), + ), + |&(path, _point1), &point2| (path, point2), + ); + + // path_maybe_uninitialized_on_exit(path, point2) :- + // path_maybe_uninitialized_on_exit(path, point1), + // cfg_edge(point1, point2) + // !path_assigned_at(path, point2). + path_maybe_uninitialized_on_exit.from_leapjoin( + &path_maybe_uninitialized_on_exit, + ( + cfg_edge.extend_with(|&(_path, point1)| point1), + ctx.path_assigned_at.extend_anti(|&(path, _point1)| path), + ), + |&(path, _point1), &point2| (path, point2), + ); + + // var_maybe_partly_initialized_on_exit(var, point) :- + // path_maybe_initialized_on_exit(path, point). + // path_begins_with_var(path, var). + var_maybe_partly_initialized_on_exit.from_leapjoin( + &path_maybe_initialized_on_exit, + ctx.path_begins_with_var.extend_with(|&(path, _point)| path), + |&(_path, point), &var| (var, point), + ); + + // move_error(Path, TargetNode) :- + // path_maybe_uninitialized_on_exit(Path, SourceNode), + // cfg_edge(SourceNode, TargetNode), + // path_accessed_at(Path, TargetNode). + move_error.from_leapjoin( + &path_maybe_uninitialized_on_exit, + ( + cfg_edge.extend_with(|&(_path, source_node)| source_node), + ctx.path_accessed_at + .extend_with(|&(path, _source_node)| path), + ), + |&(path, _source_node), &target_node| (path, target_node), + ); + } + + if output.dump_enabled { + for &(path, location) in path_maybe_initialized_on_exit.complete().iter() { + output + .path_maybe_initialized_on_exit + .entry(location) + .or_default() + .push(path); + } + + for &(path, location) in path_maybe_uninitialized_on_exit.complete().iter() { + output + .path_maybe_uninitialized_on_exit + .entry(location) + .or_default() + .push(path); + } + } + + InitializationStatus { + var_maybe_partly_initialized_on_exit: var_maybe_partly_initialized_on_exit.complete(), + move_error: move_error.complete(), + } +} + +// Compute two things: +// +// - an over-approximation of the initialization of variables. This is used in +// the origin_live_on_entry computations to determine when a drop may happen; a +// definitely moved variable would not be actually dropped. +// - move errors. +// +// The process is split into two stages: +// +// 1. Compute the transitive closure of path accesses. That is, accessing `f.a` +// would access `f.a.b`, etc. +// 2. Use this to compute both paths that may be initialized and paths that may +// have been deinitialized, which in turn can be used to find move errors (an +// access to a path that may be deinitialized). +pub(super) fn compute<T: FactTypes>( + ctx: InitializationContext<T>, + cfg_edge: &Relation<(T::Point, T::Point)>, + output: &mut Output<T>, +) -> InitializationResult<T> { + let timer = Instant::now(); + + let transitive_paths = compute_transitive_paths::<T>( + ctx.child_path, + ctx.path_assigned_at_base, + ctx.path_moved_at_base, + ctx.path_accessed_at_base, + ctx.path_is_var, + ); + info!("initialization phase 1 completed: {:?}", timer.elapsed()); + + let InitializationStatus { + var_maybe_partly_initialized_on_exit, + move_error, + } = compute_move_errors::<T>(transitive_paths, cfg_edge, output); + info!( + "initialization phase 2: {} move errors in {:?}", + move_error.elements.len(), + timer.elapsed() + ); + + if output.dump_enabled { + for &(var, location) in var_maybe_partly_initialized_on_exit.iter() { + output + .var_maybe_partly_initialized_on_exit + .entry(location) + .or_default() + .push(var); + } + } + + InitializationResult(var_maybe_partly_initialized_on_exit, move_error) +} diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/output/liveness.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/output/liveness.rs new file mode 100644 index 0000000..1b4b4ce --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/output/liveness.rs @@ -0,0 +1,170 @@ +// Copyright 2019 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! An implementation of the origin liveness calculation logic + +use std::collections::BTreeSet; +use std::time::Instant; + +use crate::facts::FactTypes; +use crate::output::{LivenessContext, Output}; + +use datafrog::{Iteration, Relation, RelationLeaper}; + +pub(super) fn compute_live_origins<T: FactTypes>( + ctx: LivenessContext<T>, + cfg_edge: &Relation<(T::Point, T::Point)>, + var_maybe_partly_initialized_on_exit: Relation<(T::Variable, T::Point)>, + output: &mut Output<T>, +) -> Vec<(T::Origin, T::Point)> { + let timer = Instant::now(); + let mut iteration = Iteration::new(); + + // Relations + let var_defined_at: Relation<(T::Variable, T::Point)> = ctx.var_defined_at.into(); + let cfg_edge_reverse: Relation<(T::Point, T::Point)> = cfg_edge + .iter() + .map(|&(point1, point2)| (point2, point1)) + .collect(); + let use_of_var_derefs_origin: Relation<(T::Variable, T::Origin)> = + ctx.use_of_var_derefs_origin.into(); + let drop_of_var_derefs_origin: Relation<(T::Variable, T::Origin)> = + ctx.drop_of_var_derefs_origin.into(); + let var_dropped_at: Relation<((T::Variable, T::Point), ())> = ctx + .var_dropped_at + .into_iter() + .map(|(var, point)| ((var, point), ())) + .collect(); + + // Variables + + // `var_live_on_entry`: variable `var` is live upon entry at `point` + let var_live_on_entry = iteration.variable::<(T::Variable, T::Point)>("var_live_on_entry"); + // `var_drop_live_on_entry`: variable `var` is drop-live (will be used for a drop) upon entry in `point` + let var_drop_live_on_entry = + iteration.variable::<(T::Variable, T::Point)>("var_drop_live_on_entry"); + + // This is what we are actually calculating: + let origin_live_on_entry = iteration.variable::<(T::Origin, T::Point)>("origin_live_on_entry"); + + // This propagates the relation `var_live_on_entry(var, point) :- var_used_at(var, point)`: + var_live_on_entry.insert(ctx.var_used_at.into()); + + // var_maybe_partly_initialized_on_entry(var, point2) :- + // var_maybe_partly_initialized_on_exit(var, point1), + // cfg_edge(point1, point2). + let var_maybe_partly_initialized_on_entry = Relation::from_leapjoin( + &var_maybe_partly_initialized_on_exit, + cfg_edge.extend_with(|&(_var, point1)| point1), + |&(var, _point1), &point2| ((var, point2), ()), + ); + + // var_drop_live_on_entry(var, point) :- + // var_dropped_at(var, point), + // var_maybe_partly_initialized_on_entry(var, point). + var_drop_live_on_entry.insert(Relation::from_join( + &var_dropped_at, + &var_maybe_partly_initialized_on_entry, + |&(var, point), _, _| (var, point), + )); + + while iteration.changed() { + // origin_live_on_entry(origin, point) :- + // var_drop_live_on_entry(var, point), + // drop_of_var_derefs_origin(var, origin). + origin_live_on_entry.from_join( + &var_drop_live_on_entry, + &drop_of_var_derefs_origin, + |_var, &point, &origin| (origin, point), + ); + + // origin_live_on_entry(origin, point) :- + // var_live_on_entry(var, point), + // use_of_var_derefs_origin(var, origin). + origin_live_on_entry.from_join( + &var_live_on_entry, + &use_of_var_derefs_origin, + |_var, &point, &origin| (origin, point), + ); + + // var_live_on_entry(var, point1) :- + // var_live_on_entry(var, point2), + // cfg_edge(point1, point2), + // !var_defined(var, point1). + var_live_on_entry.from_leapjoin( + &var_live_on_entry, + ( + var_defined_at.extend_anti(|&(var, _point2)| var), + cfg_edge_reverse.extend_with(|&(_var, point2)| point2), + ), + |&(var, _point2), &point1| (var, point1), + ); + + // var_drop_live_on_entry(Var, SourceNode) :- + // var_drop_live_on_entry(Var, TargetNode), + // cfg_edge(SourceNode, TargetNode), + // !var_defined_at(Var, SourceNode), + // var_maybe_partly_initialized_on_exit(Var, SourceNode). + var_drop_live_on_entry.from_leapjoin( + &var_drop_live_on_entry, + ( + var_defined_at.extend_anti(|&(var, _target_node)| var), + cfg_edge_reverse.extend_with(|&(_var, target_node)| target_node), + var_maybe_partly_initialized_on_exit.extend_with(|&(var, _target_node)| var), + ), + |&(var, _targetnode), &source_node| (var, source_node), + ); + } + + let origin_live_on_entry = origin_live_on_entry.complete(); + + info!( + "compute_live_origins() completed: {} tuples, {:?}", + origin_live_on_entry.len(), + timer.elapsed(), + ); + + if output.dump_enabled { + let var_drop_live_on_entry = var_drop_live_on_entry.complete(); + for &(var, location) in var_drop_live_on_entry.iter() { + output + .var_drop_live_on_entry + .entry(location) + .or_default() + .push(var); + } + + let var_live_on_entry = var_live_on_entry.complete(); + for &(var, location) in var_live_on_entry.iter() { + output + .var_live_on_entry + .entry(location) + .or_default() + .push(var); + } + } + + origin_live_on_entry.elements +} + +pub(super) fn make_universal_regions_live<T: FactTypes>( + origin_live_on_entry: &mut Vec<(T::Origin, T::Point)>, + cfg_node: &BTreeSet<T::Point>, + universal_regions: &[T::Origin], +) { + debug!("make_universal_regions_live()"); + + origin_live_on_entry.reserve(universal_regions.len() * cfg_node.len()); + for &origin in universal_regions.iter() { + for &point in cfg_node.iter() { + origin_live_on_entry.push((origin, point)); + } + } +} diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/output/location_insensitive.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/output/location_insensitive.rs new file mode 100644 index 0000000..83ce277 --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/output/location_insensitive.rs @@ -0,0 +1,156 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use datafrog::{Iteration, Relation, RelationLeaper}; +use std::time::Instant; + +use crate::facts::FactTypes; +use crate::output::{Context, Output}; + +pub(super) fn compute<T: FactTypes>( + ctx: &Context<'_, T>, + result: &mut Output<T>, +) -> ( + Relation<(T::Loan, T::Point)>, + Relation<(T::Origin, T::Origin)>, +) { + let timer = Instant::now(); + + let (potential_errors, potential_subset_errors) = { + // Static inputs + let origin_live_on_entry = &ctx.origin_live_on_entry; + let loan_invalidated_at = &ctx.loan_invalidated_at; + let placeholder_origin = &ctx.placeholder_origin; + let placeholder_loan = &ctx.placeholder_loan; + let known_contains = &ctx.known_contains; + + // subset(Origin1, Origin2) :- + // subset_base(Origin1, Origin2, _). + let subset = Relation::from_iter( + ctx.subset_base + .iter() + .map(|&(origin1, origin2, _point)| (origin1, origin2)), + ); + + // Create a new iteration context, ... + let mut iteration = Iteration::new(); + + // .. some variables, .. + let origin_contains_loan_on_entry = + iteration.variable::<(T::Origin, T::Loan)>("origin_contains_loan_on_entry"); + + let potential_errors = iteration.variable::<(T::Loan, T::Point)>("potential_errors"); + let potential_subset_errors = + iteration.variable::<(T::Origin, T::Origin)>("potential_subset_errors"); + + // load initial facts. + + // origin_contains_loan_on_entry(Origin, Loan) :- + // loan_issued_at(Origin, Loan, _). + origin_contains_loan_on_entry.extend( + ctx.loan_issued_at + .iter() + .map(|&(origin, loan, _point)| (origin, loan)), + ); + + // origin_contains_loan_on_entry(Origin, Loan) :- + // placeholder_loan(Origin, Loan). + origin_contains_loan_on_entry.extend( + placeholder_loan + .iter() + .map(|&(loan, origin)| (origin, loan)), + ); + + // .. and then start iterating rules! + while iteration.changed() { + // origin_contains_loan_on_entry(Origin2, Loan) :- + // origin_contains_loan_on_entry(Origin1, Loan), + // subset(Origin1, Origin2). + // + // Note: Since `subset` is effectively a static input, this join can be ported to + // a leapjoin. Doing so, however, was 7% slower on `clap`. + origin_contains_loan_on_entry.from_join( + &origin_contains_loan_on_entry, + &subset, + |&_origin1, &loan, &origin2| (origin2, loan), + ); + + // loan_live_at(Loan, Point) :- + // origin_contains_loan_on_entry(Origin, Loan), + // origin_live_on_entry(Origin, Point) + // + // potential_errors(Loan, Point) :- + // loan_invalidated_at(Loan, Point), + // loan_live_at(Loan, Point). + // + // Note: we don't need to materialize `loan_live_at` here + // so we can inline it in the `potential_errors` relation. + // + potential_errors.from_leapjoin( + &origin_contains_loan_on_entry, + ( + origin_live_on_entry.extend_with(|&(origin, _loan)| origin), + loan_invalidated_at.extend_with(|&(_origin, loan)| loan), + ), + |&(_origin, loan), &point| (loan, point), + ); + + // potential_subset_errors(Origin1, Origin2) :- + // placeholder(Origin1, Loan1), + // placeholder(Origin2, _), + // origin_contains_loan_on_entry(Origin2, Loan1), + // !known_contains(Origin2, Loan1). + potential_subset_errors.from_leapjoin( + &origin_contains_loan_on_entry, + ( + known_contains.filter_anti(|&(origin2, loan1)| (origin2, loan1)), + placeholder_origin.filter_with(|&(origin2, _loan1)| (origin2, ())), + placeholder_loan.extend_with(|&(_origin2, loan1)| loan1), + // remove symmetries: + datafrog::ValueFilter::from(|&(origin2, _loan1), &origin1| origin2 != origin1), + ), + |&(origin2, _loan1), &origin1| (origin1, origin2), + ); + } + + if result.dump_enabled { + for &(origin1, origin2) in subset.iter() { + result + .subset_anywhere + .entry(origin1) + .or_default() + .insert(origin2); + } + + let origin_contains_loan_on_entry = origin_contains_loan_on_entry.complete(); + for &(origin, loan) in origin_contains_loan_on_entry.iter() { + result + .origin_contains_loan_anywhere + .entry(origin) + .or_default() + .insert(loan); + } + } + + ( + potential_errors.complete(), + potential_subset_errors.complete(), + ) + }; + + info!( + "analysis done: {} `potential_errors` tuples, {} `potential_subset_errors` tuples, {:?}", + potential_errors.len(), + potential_subset_errors.len(), + timer.elapsed() + ); + + (potential_errors, potential_subset_errors) +} diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/output/mod.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/output/mod.rs new file mode 100644 index 0000000..b840e4b --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/output/mod.rs @@ -0,0 +1,614 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use datafrog::Relation; +use rustc_hash::{FxHashMap, FxHashSet}; +use std::borrow::Cow; +use std::collections::{BTreeMap, BTreeSet}; + +use crate::facts::{AllFacts, Atom, FactTypes}; + +mod datafrog_opt; +mod initialization; +mod liveness; +mod location_insensitive; +mod naive; + +#[derive(Debug, Clone, Copy)] +pub enum Algorithm { + /// Simple rules, but slower to execute + Naive, + + /// Optimized variant of the rules + DatafrogOpt, + + /// Fast to compute, but imprecise: there can be false-positives + /// but no false-negatives. Tailored for quick "early return" situations. + LocationInsensitive, + + /// Compares the `Naive` and `DatafrogOpt` variants to ensure they indeed + /// compute the same errors. + Compare, + + /// Combination of the fast `LocationInsensitive` pre-pass, followed by + /// the more expensive `DatafrogOpt` variant. + Hybrid, +} + +impl Algorithm { + /// Optimized variants that ought to be equivalent to "naive" + pub const OPTIMIZED: &'static [Algorithm] = &[Algorithm::DatafrogOpt]; + + pub fn variants() -> [&'static str; 5] { + [ + "Naive", + "DatafrogOpt", + "LocationInsensitive", + "Compare", + "Hybrid", + ] + } +} + +impl ::std::str::FromStr for Algorithm { + type Err = String; + fn from_str(s: &str) -> Result<Self, Self::Err> { + match s.to_lowercase().as_ref() { + "naive" => Ok(Algorithm::Naive), + "datafrogopt" => Ok(Algorithm::DatafrogOpt), + "locationinsensitive" => Ok(Algorithm::LocationInsensitive), + "compare" => Ok(Algorithm::Compare), + "hybrid" => Ok(Algorithm::Hybrid), + _ => Err(String::from( + "valid values: Naive, DatafrogOpt, LocationInsensitive, Compare, Hybrid", + )), + } + } +} + +#[derive(Clone, Debug)] +pub struct Output<T: FactTypes> { + pub errors: FxHashMap<T::Point, Vec<T::Loan>>, + pub subset_errors: FxHashMap<T::Point, BTreeSet<(T::Origin, T::Origin)>>, + pub move_errors: FxHashMap<T::Point, Vec<T::Path>>, + + pub dump_enabled: bool, + + // these are just for debugging + pub loan_live_at: FxHashMap<T::Point, Vec<T::Loan>>, + pub origin_contains_loan_at: FxHashMap<T::Point, BTreeMap<T::Origin, BTreeSet<T::Loan>>>, + pub origin_contains_loan_anywhere: FxHashMap<T::Origin, BTreeSet<T::Loan>>, + pub origin_live_on_entry: FxHashMap<T::Point, Vec<T::Origin>>, + pub loan_invalidated_at: FxHashMap<T::Point, Vec<T::Loan>>, + pub subset: FxHashMap<T::Point, BTreeMap<T::Origin, BTreeSet<T::Origin>>>, + pub subset_anywhere: FxHashMap<T::Origin, BTreeSet<T::Origin>>, + pub var_live_on_entry: FxHashMap<T::Point, Vec<T::Variable>>, + pub var_drop_live_on_entry: FxHashMap<T::Point, Vec<T::Variable>>, + pub path_maybe_initialized_on_exit: FxHashMap<T::Point, Vec<T::Path>>, + pub path_maybe_uninitialized_on_exit: FxHashMap<T::Point, Vec<T::Path>>, + pub known_contains: FxHashMap<T::Origin, BTreeSet<T::Loan>>, + pub var_maybe_partly_initialized_on_exit: FxHashMap<T::Point, Vec<T::Variable>>, +} + +/// Subset of `AllFacts` dedicated to initialization +struct InitializationContext<T: FactTypes> { + child_path: Vec<(T::Path, T::Path)>, + path_is_var: Vec<(T::Path, T::Variable)>, + path_assigned_at_base: Vec<(T::Path, T::Point)>, + path_moved_at_base: Vec<(T::Path, T::Point)>, + path_accessed_at_base: Vec<(T::Path, T::Point)>, +} + +/// Subset of `AllFacts` dedicated to liveness +struct LivenessContext<T: FactTypes> { + var_used_at: Vec<(T::Variable, T::Point)>, + var_defined_at: Vec<(T::Variable, T::Point)>, + var_dropped_at: Vec<(T::Variable, T::Point)>, + use_of_var_derefs_origin: Vec<(T::Variable, T::Origin)>, + drop_of_var_derefs_origin: Vec<(T::Variable, T::Origin)>, +} + +/// Subset of `AllFacts` dedicated to borrow checking, and data ready to use by the variants +struct Context<'ctx, T: FactTypes> { + // `Relation`s used as static inputs, by all variants + origin_live_on_entry: Relation<(T::Origin, T::Point)>, + loan_invalidated_at: Relation<(T::Loan, T::Point)>, + + // static inputs used via `Variable`s, by all variants + subset_base: &'ctx Vec<(T::Origin, T::Origin, T::Point)>, + loan_issued_at: &'ctx Vec<(T::Origin, T::Loan, T::Point)>, + + // static inputs used by variants other than `LocationInsensitive` + loan_killed_at: Relation<(T::Loan, T::Point)>, + known_contains: Relation<(T::Origin, T::Loan)>, + placeholder_origin: Relation<(T::Origin, ())>, + placeholder_loan: Relation<(T::Loan, T::Origin)>, + + // The `known_placeholder_subset` relation in the facts does not necessarily contain all the + // transitive subsets. The transitive closure is always needed, so this version here is fully + // closed over. + known_placeholder_subset: Relation<(T::Origin, T::Origin)>, + + // while this static input is unused by `LocationInsensitive`, it's depended on by + // initialization and liveness, so already computed by the time we get to borrowcking. + cfg_edge: Relation<(T::Point, T::Point)>, + + // Partial results possibly used by other variants as input. Not currently used yet. + #[allow(dead_code)] + potential_errors: Option<FxHashSet<T::Loan>>, + #[allow(dead_code)] + potential_subset_errors: Option<Relation<(T::Origin, T::Origin)>>, +} + +impl<T: FactTypes> Output<T> { + /// All variants require the same initial preparations, done in multiple + /// successive steps: + /// - compute initialization data + /// - compute liveness + /// - prepare static inputs as shared `Relation`s + /// - in cases where `LocationInsensitive` variant is ran as a filtering pre-pass, + /// partial results can also be stored in the context, so that the following + /// variant can use it to prune its own input data + pub fn compute(all_facts: &AllFacts<T>, algorithm: Algorithm, dump_enabled: bool) -> Self { + let mut result = Output::new(dump_enabled); + + // TODO: remove all the cloning thereafter, but that needs to be done in concert with rustc + + let cfg_edge = all_facts.cfg_edge.clone().into(); + + // 1) Initialization + let initialization_ctx = InitializationContext { + child_path: all_facts.child_path.clone(), + path_is_var: all_facts.path_is_var.clone(), + path_assigned_at_base: all_facts.path_assigned_at_base.clone(), + path_moved_at_base: all_facts.path_moved_at_base.clone(), + path_accessed_at_base: all_facts.path_accessed_at_base.clone(), + }; + + let initialization::InitializationResult::<T>( + var_maybe_partly_initialized_on_exit, + move_errors, + ) = initialization::compute(initialization_ctx, &cfg_edge, &mut result); + + // FIXME: move errors should prevent the computation from continuing: we can't compute + // liveness and analyze loans accurately when there are move errors, and should early + // return here. + for &(path, location) in move_errors.iter() { + result.move_errors.entry(location).or_default().push(path); + } + + // 2) Liveness + let liveness_ctx = LivenessContext { + var_used_at: all_facts.var_used_at.clone(), + var_defined_at: all_facts.var_defined_at.clone(), + var_dropped_at: all_facts.var_dropped_at.clone(), + use_of_var_derefs_origin: all_facts.use_of_var_derefs_origin.clone(), + drop_of_var_derefs_origin: all_facts.drop_of_var_derefs_origin.clone(), + }; + + let mut origin_live_on_entry = liveness::compute_live_origins( + liveness_ctx, + &cfg_edge, + var_maybe_partly_initialized_on_exit, + &mut result, + ); + + let cfg_node = cfg_edge + .iter() + .map(|&(point1, _)| point1) + .chain(cfg_edge.iter().map(|&(_, point2)| point2)) + .collect(); + + liveness::make_universal_regions_live::<T>( + &mut origin_live_on_entry, + &cfg_node, + &all_facts.universal_region, + ); + + // 3) Borrow checking + + // Prepare data as datafrog relations, ready to join. + // + // Note: if rustc and polonius had more interaction, we could also delay or avoid + // generating some of the facts that are now always present here. For example, + // the `LocationInsensitive` variant doesn't use the `loan_killed_at` relation, so we could + // technically delay computing and passing it from rustc, when using this or the `Hybrid` + // variants, to after the pre-pass has made sure we actually need to compute the full + // analysis. If these facts happened to be recorded in separate MIR walks, we might also + // avoid generating those facts. + + let origin_live_on_entry = origin_live_on_entry.into(); + + // TODO: also flip the order of this relation's arguments in rustc + // from `loan_invalidated_at(point, loan)` to `loan_invalidated_at(loan, point)`. + // to avoid this allocation. + let loan_invalidated_at = Relation::from_iter( + all_facts + .loan_invalidated_at + .iter() + .map(|&(point, loan)| (loan, point)), + ); + + let loan_killed_at = all_facts.loan_killed_at.clone().into(); + + // `known_placeholder_subset` is a list of all the `'a: 'b` subset relations the user gave: + // it's not required to be transitive. `known_contains` is its transitive closure: a list + // of all the known placeholder loans that each of these placeholder origins contains. + // Given the `known_placeholder_subset`s `'a: 'b` and `'b: 'c`: in the `known_contains` + // relation, `'a` will also contain `'c`'s placeholder loan. + let known_placeholder_subset = all_facts.known_placeholder_subset.clone().into(); + let known_contains = + Output::<T>::compute_known_contains(&known_placeholder_subset, &all_facts.placeholder); + + // Fully close over the `known_placeholder_subset` relation. + let known_placeholder_subset = + Output::<T>::compute_known_placeholder_subset(&known_placeholder_subset); + + let placeholder_origin: Relation<_> = Relation::from_iter( + all_facts + .universal_region + .iter() + .map(|&origin| (origin, ())), + ); + + let placeholder_loan = Relation::from_iter( + all_facts + .placeholder + .iter() + .map(|&(origin, loan)| (loan, origin)), + ); + + // Ask the variants to compute errors in their own way + let mut ctx = Context { + origin_live_on_entry, + loan_invalidated_at, + cfg_edge, + subset_base: &all_facts.subset_base, + loan_issued_at: &all_facts.loan_issued_at, + loan_killed_at, + known_contains, + known_placeholder_subset, + placeholder_origin, + placeholder_loan, + potential_errors: None, + potential_subset_errors: None, + }; + + let (errors, subset_errors) = match algorithm { + Algorithm::LocationInsensitive => { + let (potential_errors, potential_subset_errors) = + location_insensitive::compute(&ctx, &mut result); + + // Note: the error location is meaningless for a location-insensitive + // subset error analysis. This is acceptable here as this variant is not one + // which should be used directly besides debugging, the `Hybrid` variant will + // take advantage of its result. + let potential_subset_errors: Relation<(T::Origin, T::Origin, T::Point)> = + Relation::from_iter( + potential_subset_errors + .into_iter() + .map(|&(origin1, origin2)| (origin1, origin2, 0.into())), + ); + + (potential_errors, potential_subset_errors) + } + Algorithm::Naive => naive::compute(&ctx, &mut result), + Algorithm::DatafrogOpt => datafrog_opt::compute(&ctx, &mut result), + Algorithm::Hybrid => { + // Execute the fast `LocationInsensitive` computation as a pre-pass: + // if it finds no possible errors, we don't need to do the more complex + // computations as they won't find errors either, and we can return early. + let (potential_errors, potential_subset_errors) = + location_insensitive::compute(&ctx, &mut result); + + if potential_errors.is_empty() && potential_subset_errors.is_empty() { + // There are no loan errors, nor subset errors, we can early return + // empty errors lists and avoid doing the heavy analysis. + (potential_errors, Vec::new().into()) + } else { + // Record these potential errors as they can be used to limit the next + // variant's work to only these loans. + ctx.potential_errors = + Some(potential_errors.iter().map(|&(loan, _)| loan).collect()); + ctx.potential_subset_errors = Some(potential_subset_errors); + + datafrog_opt::compute(&ctx, &mut result) + } + } + Algorithm::Compare => { + // Ensure the `Naive` and `DatafrogOpt` errors are the same + let (naive_errors, naive_subset_errors) = naive::compute(&ctx, &mut result); + let (opt_errors, _) = datafrog_opt::compute(&ctx, &mut result); + + // TODO: compare illegal subset relations errors as well here ? + + let mut naive_errors_by_point = FxHashMap::default(); + for &(loan, point) in naive_errors.iter() { + naive_errors_by_point + .entry(point) + .or_insert_with(Vec::new) + .push(loan); + } + + let mut opt_errors_by_point = FxHashMap::default(); + for &(loan, point) in opt_errors.iter() { + opt_errors_by_point + .entry(point) + .or_insert_with(Vec::new) + .push(loan); + } + + if compare_errors(&naive_errors_by_point, &opt_errors_by_point) { + panic!(concat!( + "The errors reported by the naive algorithm differ from ", + "the errors reported by the optimized algorithm. ", + "See the error log for details." + )); + } else { + debug!("Naive and optimized algorithms reported the same errors."); + } + + (naive_errors, naive_subset_errors) + } + }; + + // Record illegal access errors + for &(loan, location) in errors.iter() { + result.errors.entry(location).or_default().push(loan); + } + + // Record illegal subset errors + for &(origin1, origin2, location) in subset_errors.iter() { + result + .subset_errors + .entry(location) + .or_default() + .insert((origin1, origin2)); + } + + // Record more debugging info when asked to do so + if dump_enabled { + for &(origin, location) in ctx.origin_live_on_entry.iter() { + result + .origin_live_on_entry + .entry(location) + .or_default() + .push(origin); + } + + for &(origin, loan) in ctx.known_contains.iter() { + result + .known_contains + .entry(origin) + .or_default() + .insert(loan); + } + } + + result + } + + /// Computes the transitive closure of the `known_placeholder_subset` relation, so that we have + /// the full list of placeholder loans contained by the placeholder origins. + fn compute_known_contains( + known_placeholder_subset: &Relation<(T::Origin, T::Origin)>, + placeholder: &[(T::Origin, T::Loan)], + ) -> Relation<(T::Origin, T::Loan)> { + let mut iteration = datafrog::Iteration::new(); + let known_contains = iteration.variable("known_contains"); + + // known_contains(Origin1, Loan1) :- + // placeholder(Origin1, Loan1). + known_contains.extend(placeholder.iter()); + + while iteration.changed() { + // known_contains(Origin2, Loan1) :- + // known_contains(Origin1, Loan1), + // known_placeholder_subset(Origin1, Origin2). + known_contains.from_join( + &known_contains, + known_placeholder_subset, + |&_origin1, &loan1, &origin2| (origin2, loan1), + ); + } + + known_contains.complete() + } + + /// Computes the transitive closure of the `known_placeholder_subset` relation. + fn compute_known_placeholder_subset( + known_placeholder_subset_base: &Relation<(T::Origin, T::Origin)>, + ) -> Relation<(T::Origin, T::Origin)> { + use datafrog::{Iteration, RelationLeaper}; + let mut iteration = Iteration::new(); + + let known_placeholder_subset = iteration.variable("known_placeholder_subset"); + + // known_placeholder_subset(Origin1, Origin2) :- + // known_placeholder_subset_base(Origin1, Origin2). + known_placeholder_subset.extend(known_placeholder_subset_base.iter()); + + while iteration.changed() { + // known_placeholder_subset(Origin1, Origin3) :- + // known_placeholder_subset(Origin1, Origin2), + // known_placeholder_subset_base(Origin2, Origin3). + known_placeholder_subset.from_leapjoin( + &known_placeholder_subset, + known_placeholder_subset_base.extend_with(|&(_origin1, origin2)| origin2), + |&(origin1, _origin2), &origin3| (origin1, origin3), + ); + } + + known_placeholder_subset.complete() + } + + fn new(dump_enabled: bool) -> Self { + Output { + errors: FxHashMap::default(), + subset_errors: FxHashMap::default(), + dump_enabled, + loan_live_at: FxHashMap::default(), + origin_contains_loan_at: FxHashMap::default(), + origin_contains_loan_anywhere: FxHashMap::default(), + origin_live_on_entry: FxHashMap::default(), + loan_invalidated_at: FxHashMap::default(), + move_errors: FxHashMap::default(), + subset: FxHashMap::default(), + subset_anywhere: FxHashMap::default(), + var_live_on_entry: FxHashMap::default(), + var_drop_live_on_entry: FxHashMap::default(), + path_maybe_initialized_on_exit: FxHashMap::default(), + path_maybe_uninitialized_on_exit: FxHashMap::default(), + var_maybe_partly_initialized_on_exit: FxHashMap::default(), + known_contains: FxHashMap::default(), + } + } + + pub fn errors_at(&self, location: T::Point) -> &[T::Loan] { + match self.errors.get(&location) { + Some(v) => v, + None => &[], + } + } + + pub fn loans_in_scope_at(&self, location: T::Point) -> &[T::Loan] { + match self.loan_live_at.get(&location) { + Some(p) => p, + None => &[], + } + } + + pub fn origin_contains_loan_at( + &self, + location: T::Point, + ) -> Cow<'_, BTreeMap<T::Origin, BTreeSet<T::Loan>>> { + assert!(self.dump_enabled); + match self.origin_contains_loan_at.get(&location) { + Some(map) => Cow::Borrowed(map), + None => Cow::Owned(BTreeMap::default()), + } + } + + pub fn origins_live_at(&self, location: T::Point) -> &[T::Origin] { + assert!(self.dump_enabled); + match self.origin_live_on_entry.get(&location) { + Some(v) => v, + None => &[], + } + } + + pub fn subsets_at( + &self, + location: T::Point, + ) -> Cow<'_, BTreeMap<T::Origin, BTreeSet<T::Origin>>> { + assert!(self.dump_enabled); + match self.subset.get(&location) { + Some(v) => Cow::Borrowed(v), + None => Cow::Owned(BTreeMap::default()), + } + } +} + +/// Compares errors reported by Naive implementation with the errors +/// reported by the optimized implementation. +fn compare_errors<Loan: Atom, Point: Atom>( + all_naive_errors: &FxHashMap<Point, Vec<Loan>>, + all_opt_errors: &FxHashMap<Point, Vec<Loan>>, +) -> bool { + let points = all_naive_errors.keys().chain(all_opt_errors.keys()); + + let mut differ = false; + for point in points { + let mut naive_errors = all_naive_errors.get(&point).cloned().unwrap_or_default(); + naive_errors.sort(); + + let mut opt_errors = all_opt_errors.get(&point).cloned().unwrap_or_default(); + opt_errors.sort(); + + for err in naive_errors.iter() { + if !opt_errors.contains(err) { + error!( + "Error {0:?} at {1:?} reported by naive, but not opt.", + err, point + ); + differ = true; + } + } + + for err in opt_errors.iter() { + if !naive_errors.contains(err) { + error!( + "Error {0:?} at {1:?} reported by opt, but not naive.", + err, point + ); + differ = true; + } + } + } + + differ +} + +#[cfg(test)] +mod tests { + use super::*; + + impl Atom for usize { + fn index(self) -> usize { + self + } + } + + fn compare( + errors1: &FxHashMap<usize, Vec<usize>>, + errors2: &FxHashMap<usize, Vec<usize>>, + ) -> bool { + let diff1 = compare_errors(errors1, errors2); + let diff2 = compare_errors(errors2, errors1); + assert_eq!(diff1, diff2); + diff1 + } + + #[test] + fn test_compare_errors() { + let empty = FxHashMap::default(); + assert_eq!(false, compare(&empty, &empty)); + let mut empty_vec = FxHashMap::default(); + empty_vec.insert(1, vec![]); + empty_vec.insert(2, vec![]); + assert_eq!(false, compare(&empty, &empty_vec)); + + let mut singleton1 = FxHashMap::default(); + singleton1.insert(1, vec![10]); + assert_eq!(false, compare(&singleton1, &singleton1)); + let mut singleton2 = FxHashMap::default(); + singleton2.insert(1, vec![11]); + assert_eq!(false, compare(&singleton2, &singleton2)); + let mut singleton3 = FxHashMap::default(); + singleton3.insert(2, vec![10]); + assert_eq!(false, compare(&singleton3, &singleton3)); + + assert_eq!(true, compare(&singleton1, &singleton2)); + assert_eq!(true, compare(&singleton2, &singleton3)); + assert_eq!(true, compare(&singleton1, &singleton3)); + + assert_eq!(true, compare(&empty, &singleton1)); + assert_eq!(true, compare(&empty, &singleton2)); + assert_eq!(true, compare(&empty, &singleton3)); + + let mut errors1 = FxHashMap::default(); + errors1.insert(1, vec![11]); + errors1.insert(2, vec![10]); + assert_eq!(false, compare(&errors1, &errors1)); + assert_eq!(true, compare(&errors1, &singleton1)); + assert_eq!(true, compare(&errors1, &singleton2)); + assert_eq!(true, compare(&errors1, &singleton3)); + } +} diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/output/naive.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/output/naive.rs new file mode 100644 index 0000000..aa42048 --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/output/naive.rs @@ -0,0 +1,299 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A version of the Naive datalog analysis using Datafrog. + +use datafrog::{Iteration, Relation, RelationLeaper}; +use std::time::Instant; + +use crate::facts::FactTypes; +use crate::output::{Context, Output}; + +pub(super) fn compute<T: FactTypes>( + ctx: &Context<'_, T>, + result: &mut Output<T>, +) -> ( + Relation<(T::Loan, T::Point)>, + Relation<(T::Origin, T::Origin, T::Point)>, +) { + let timer = Instant::now(); + + let (errors, subset_errors) = { + // Static inputs + let origin_live_on_entry_rel = &ctx.origin_live_on_entry; + let cfg_edge = &ctx.cfg_edge; + let loan_killed_at = &ctx.loan_killed_at; + let known_placeholder_subset = &ctx.known_placeholder_subset; + let placeholder_origin = &ctx.placeholder_origin; + + // Create a new iteration context, ... + let mut iteration = Iteration::new(); + + // .. some variables, .. + let subset = iteration.variable::<(T::Origin, T::Origin, T::Point)>("subset"); + let origin_contains_loan_on_entry = + iteration.variable::<(T::Origin, T::Loan, T::Point)>("origin_contains_loan_on_entry"); + let loan_live_at = iteration.variable::<((T::Loan, T::Point), ())>("loan_live_at"); + + // `loan_invalidated_at` facts, stored ready for joins + let loan_invalidated_at = Relation::from_iter( + ctx.loan_invalidated_at + .iter() + .map(|&(loan, point)| ((loan, point), ())), + ); + + // different indices for `subset`. + let subset_o1p = iteration.variable_indistinct("subset_o1p"); + let subset_o2p = iteration.variable_indistinct("subset_o2p"); + + // different index for `origin_contains_loan_on_entry`. + let origin_contains_loan_on_entry_op = + iteration.variable_indistinct("origin_contains_loan_on_entry_op"); + + // Unfortunately, we need `origin_live_on_entry` in both variable and relation forms: + // We need: + // - `origin_live_on_entry` as a Relation for the leapjoins in rules 3 & 6 + // - `origin_live_on_entry` as a Variable for the join in rule 7 + // + // The leapjoins use `origin_live_on_entry` as `(Origin, Point)` tuples, while the join uses + // it as a `((O, P), ())` tuple to filter the `((Origin, Point), Loan)` tuples from + // `origin_contains_loan_on_entry_op`. + // + // The regular join in rule 7 could be turned into a `filter_with` leaper but that would + // result in a leapjoin with no `extend_*` leapers: a leapjoin that is not well-formed. + // Doing the filtering via an `extend_with` leaper would be extremely inefficient. + // + // Until there's an API in datafrog to handle this use-case better, we do a slightly less + // inefficient thing of copying the whole static input into a Variable to use a regular + // join, even though the liveness information can be quite heavy (around 1M tuples + // on `clap`). + // This is the Naive variant so this is not a big problem, but needs an + // explanation. + let origin_live_on_entry_var = + iteration.variable::<((T::Origin, T::Point), ())>("origin_live_on_entry"); + origin_live_on_entry_var.extend( + origin_live_on_entry_rel + .iter() + .map(|&(origin, point)| ((origin, point), ())), + ); + + // output relations: illegal accesses errors, and illegal subset relations errors + let errors = iteration.variable("errors"); + let subset_errors = iteration.variable::<(T::Origin, T::Origin, T::Point)>("subset_errors"); + + // load initial facts: + + // Rule 1: the initial subsets are the non-transitive `subset_base` static input. + // + // subset(Origin1, Origin2, Point) :- + // subset_base(Origin1, Origin2, Point). + subset.extend(ctx.subset_base.iter()); + + // Rule 4: the issuing origins are the ones initially containing loans. + // + // origin_contains_loan_on_entry(Origin, Loan, Point) :- + // loan_issued_at(Origin, Loan, Point). + origin_contains_loan_on_entry.extend(ctx.loan_issued_at.iter()); + + // .. and then start iterating rules! + while iteration.changed() { + // Cleanup step: remove symmetries + // - remove origins which are `subset`s of themselves + // + // FIXME: investigate whether is there a better way to do that without complicating + // the rules too much, because it would also require temporary variables and + // impact performance. Until then, the big reduction in tuples improves performance + // a lot, even if we're potentially adding a small number of tuples + // per round just to remove them in the next round. + subset + .recent + .borrow_mut() + .elements + .retain(|&(origin1, origin2, _)| origin1 != origin2); + + // Remap fields to re-index by keys, to prepare the data needed by the rules below. + subset_o1p.from_map(&subset, |&(origin1, origin2, point)| { + ((origin1, point), origin2) + }); + subset_o2p.from_map(&subset, |&(origin1, origin2, point)| { + ((origin2, point), origin1) + }); + + origin_contains_loan_on_entry_op + .from_map(&origin_contains_loan_on_entry, |&(origin, loan, point)| { + ((origin, point), loan) + }); + + // Rule 1: done above, as part of the static input facts setup. + + // Rule 2: compute the subset transitive closure, at a given point. + // + // subset(Origin1, Origin3, Point) :- + // subset(Origin1, Origin2, Point), + // subset(Origin2, Origin3, Point). + subset.from_join( + &subset_o2p, + &subset_o1p, + |&(_origin2, point), &origin1, &origin3| (origin1, origin3, point), + ); + + // Rule 3: propagate subsets along the CFG, according to liveness. + // + // subset(Origin1, Origin2, Point2) :- + // subset(Origin1, Origin2, Point1), + // cfg_edge(Point1, Point2), + // origin_live_on_entry(Origin1, Point2), + // origin_live_on_entry(Origin2, Point2). + subset.from_leapjoin( + &subset, + ( + cfg_edge.extend_with(|&(_origin1, _origin2, point1)| point1), + origin_live_on_entry_rel.extend_with(|&(origin1, _origin2, _point1)| origin1), + origin_live_on_entry_rel.extend_with(|&(_origin1, origin2, _point1)| origin2), + ), + |&(origin1, origin2, _point1), &point2| (origin1, origin2, point2), + ); + + // Rule 4: done above as part of the static input facts setup. + + // Rule 5: propagate loans within origins, at a given point, according to subsets. + // + // origin_contains_loan_on_entry(Origin2, Loan, Point) :- + // origin_contains_loan_on_entry(Origin1, Loan, Point), + // subset(Origin1, Origin2, Point). + origin_contains_loan_on_entry.from_join( + &origin_contains_loan_on_entry_op, + &subset_o1p, + |&(_origin1, point), &loan, &origin2| (origin2, loan, point), + ); + + // Rule 6: propagate loans along the CFG, according to liveness. + // + // origin_contains_loan_on_entry(Origin, Loan, Point2) :- + // origin_contains_loan_on_entry(Origin, Loan, Point1), + // !loan_killed_at(Loan, Point1), + // cfg_edge(Point1, Point2), + // origin_live_on_entry(Origin, Point2). + origin_contains_loan_on_entry.from_leapjoin( + &origin_contains_loan_on_entry, + ( + loan_killed_at.filter_anti(|&(_origin, loan, point1)| (loan, point1)), + cfg_edge.extend_with(|&(_origin, _loan, point1)| point1), + origin_live_on_entry_rel.extend_with(|&(origin, _loan, _point1)| origin), + ), + |&(origin, loan, _point1), &point2| (origin, loan, point2), + ); + + // Rule 7: compute whether a loan is live at a given point, i.e. whether it is + // contained in a live origin at this point. + // + // loan_live_at(Loan, Point) :- + // origin_contains_loan_on_entry(Origin, Loan, Point), + // origin_live_on_entry(Origin, Point). + loan_live_at.from_join( + &origin_contains_loan_on_entry_op, + &origin_live_on_entry_var, + |&(_origin, point), &loan, _| ((loan, point), ()), + ); + + // Rule 8: compute illegal access errors, i.e. an invalidation of a live loan. + // + // Here again, this join acts as a pure filter and could be a more efficient leapjoin. + // However, similarly to the `origin_live_on_entry` example described above, the + // leapjoin with a single `filter_with` leaper would currently not be well-formed. + // We don't explictly need to materialize `loan_live_at` either, and that doesn't + // change the well-formedness situation, so we still materialize it (since that also + // helps in testing). + // + // errors(Loan, Point) :- + // loan_invalidated_at(Loan, Point), + // loan_live_at(Loan, Point). + errors.from_join( + &loan_live_at, + &loan_invalidated_at, + |&(loan, point), _, _| (loan, point), + ); + + // Rule 9: compute illegal subset relations errors, i.e. the undeclared subsets + // between two placeholder origins. + // Here as well, WF-ness prevents this join from being a filter-only leapjoin. It + // doesn't matter much, as `placeholder_origin` is single-value relation. + // + // subset_error(Origin1, Origin2, Point) :- + // subset(Origin1, Origin2, Point), + // placeholder_origin(Origin1), + // placeholder_origin(Origin2), + // !known_placeholder_subset(Origin1, Origin2). + subset_errors.from_leapjoin( + &subset, + ( + placeholder_origin.extend_with(|&(origin1, _origin2, _point)| origin1), + placeholder_origin.extend_with(|&(_origin1, origin2, _point)| origin2), + known_placeholder_subset + .filter_anti(|&(origin1, origin2, _point)| (origin1, origin2)), + // remove symmetries: + datafrog::ValueFilter::from(|&(origin1, origin2, _point), _| { + origin1 != origin2 + }), + ), + |&(origin1, origin2, point), _| (origin1, origin2, point), + ); + } + + // Handle verbose output data + if result.dump_enabled { + let subset = subset.complete(); + assert!( + subset + .iter() + .filter(|&(origin1, origin2, _)| origin1 == origin2) + .count() + == 0, + "unwanted subset symmetries" + ); + for &(origin1, origin2, location) in subset.iter() { + result + .subset + .entry(location) + .or_default() + .entry(origin1) + .or_default() + .insert(origin2); + } + + let origin_contains_loan_on_entry = origin_contains_loan_on_entry.complete(); + for &(origin, loan, location) in origin_contains_loan_on_entry.iter() { + result + .origin_contains_loan_at + .entry(location) + .or_default() + .entry(origin) + .or_default() + .insert(loan); + } + + let loan_live_at = loan_live_at.complete(); + for &((loan, location), _) in loan_live_at.iter() { + result.loan_live_at.entry(location).or_default().push(loan); + } + } + + (errors.complete(), subset_errors.complete()) + }; + + info!( + "analysis done: {} `errors` tuples, {} `subset_errors` tuples, {:?}", + errors.len(), + subset_errors.len(), + timer.elapsed() + ); + + (errors, subset_errors) +} diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/.cargo-checksum.json b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/.cargo-checksum.json new file mode 100644 index 0000000..544af9f --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CODE_OF_CONDUCT.md":"edca092fde496419a9f1ba640048aa0270b62dfea576cd3175f0b53e3c230470","Cargo.toml":"647814b27b6fc4fbef1df70d796b53b723e776b68467372044e4182763007379","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"cac8197ac869d64a6efc26cab883a269392ae6db51f7453bca722f8f31d67c7c","src/lib.rs":"ddecafb5db609d0d8eebd19e4d98dc865e7e9282a4183421f9bd765c01a231c0"},"package":"08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"}
\ No newline at end of file diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/CODE_OF_CONDUCT.md b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..d70b2b5 --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/CODE_OF_CONDUCT.md @@ -0,0 +1,40 @@ +# The Rust Code of Conduct + +A version of this document [can be found online](https://www.rust-lang.org/conduct.html). + +## Conduct + +**Contact**: [rust-mods@rust-lang.org](mailto:rust-mods@rust-lang.org) + +* We are committed to providing a friendly, safe and welcoming environment for all, regardless of level of experience, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, nationality, or other similar characteristic. +* On IRC, please avoid using overtly sexual nicknames or other nicknames that might detract from a friendly, safe and welcoming environment for all. +* Please be kind and courteous. There's no need to be mean or rude. +* Respect that people have differences of opinion and that every design or implementation choice carries a trade-off and numerous costs. There is seldom a right answer. +* Please keep unstructured critique to a minimum. If you have solid ideas you want to experiment with, make a fork and see how it works. +* We will exclude you from interaction if you insult, demean or harass anyone. That is not welcome behavior. We interpret the term "harassment" as including the definition in the <a href="http://citizencodeofconduct.org/">Citizen Code of Conduct</a>; if you have any lack of clarity about what might be included in that concept, please read their definition. In particular, we don't tolerate behavior that excludes people in socially marginalized groups. +* Private harassment is also unacceptable. No matter who you are, if you feel you have been or are being harassed or made uncomfortable by a community member, please contact one of the channel ops or any of the [Rust moderation team][mod_team] immediately. Whether you're a regular contributor or a newcomer, we care about making this community a safe place for you and we've got your back. +* Likewise any spamming, trolling, flaming, baiting or other attention-stealing behavior is not welcome. + +## Moderation + + +These are the policies for upholding our community's standards of conduct. If you feel that a thread needs moderation, please contact the [Rust moderation team][mod_team]. + +1. Remarks that violate the Rust standards of conduct, including hateful, hurtful, oppressive, or exclusionary remarks, are not allowed. (Cursing is allowed, but never targeting another user, and never in a hateful manner.) +2. Remarks that moderators find inappropriate, whether listed in the code of conduct or not, are also not allowed. +3. Moderators will first respond to such remarks with a warning. +4. If the warning is unheeded, the user will be "kicked," i.e., kicked out of the communication channel to cool off. +5. If the user comes back and continues to make trouble, they will be banned, i.e., indefinitely excluded. +6. Moderators may choose at their discretion to un-ban the user if it was a first offense and they offer the offended party a genuine apology. +7. If a moderator bans someone and you think it was unjustified, please take it up with that moderator, or with a different moderator, **in private**. Complaints about bans in-channel are not allowed. +8. Moderators are held to a higher standard than other community members. If a moderator creates an inappropriate situation, they should expect less leeway than others. + +In the Rust community we strive to go the extra step to look out for each other. Don't just aim to be technically unimpeachable, try to be your best self. In particular, avoid flirting with offensive or sensitive issues, particularly if they're off-topic; this all too often leads to unnecessary fights, hurt feelings, and damaged trust; worse, it can drive people away from the community entirely. + +And if someone takes issue with something you said or did, resist the urge to be defensive. Just stop doing what it was they complained about and apologize. Even if you feel you were misinterpreted or unfairly accused, chances are good there was something you could've communicated better — remember that it's your responsibility to make your fellow Rustaceans comfortable. Everyone wants to get along and we are all here first and foremost because we want to talk about cool technology. You will find that people will be eager to assume good intent and forgive as long as you earn their trust. + +The enforcement policies listed above apply to all official Rust venues; including official IRC channels (#rust, #rust-internals, #rust-tools, #rust-libs, #rustc, #rust-beginners, #rust-docs, #rust-community, #rust-lang, and #cargo); GitHub repositories under rust-lang, rust-lang-nursery, and rust-lang-deprecated; and all forums under rust-lang.org (users.rust-lang.org, internals.rust-lang.org). For other projects adopting the Rust Code of Conduct, please contact the maintainers of those projects for enforcement. If you wish to use this code of conduct for your own project, consider explicitly mentioning your moderation policy or making a copy with your own moderation policy so as to avoid confusion. + +*Adapted from the [Node.js Policy on Trolling](http://blog.izs.me/post/30036893703/policy-on-trolling) as well as the [Contributor Covenant v1.3.0](https://www.contributor-covenant.org/version/1/3/0/).* + +[mod_team]: https://www.rust-lang.org/team.html#Moderation-team diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/Cargo.toml b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/Cargo.toml new file mode 100644 index 0000000..47330b7 --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/Cargo.toml @@ -0,0 +1,25 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "rustc-hash" +version = "1.1.0" +authors = ["The Rust Project Developers"] +description = "speed, non-cryptographic hash used in rustc" +readme = "README.md" +keywords = ["hash", "fxhash", "rustc"] +license = "Apache-2.0/MIT" +repository = "https://github.com/rust-lang-nursery/rustc-hash" + +[features] +default = ["std"] +std = [] diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/LICENSE-APACHE b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/LICENSE-APACHE new file mode 100644 index 0000000..16fe87b --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/LICENSE-MIT b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/LICENSE-MIT new file mode 100644 index 0000000..31aa793 --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/LICENSE-MIT @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/README.md b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/README.md new file mode 100644 index 0000000..e33057a --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/README.md @@ -0,0 +1,38 @@ +# rustc-hash + +[](https://crates.io/crates/rustc-hash) +[](https://docs.rs/rustc-hash) + +A speedy hash algorithm used within rustc. The hashmap in liballoc by +default uses SipHash which isn't quite as speedy as we want. In the +compiler we're not really worried about DOS attempts, so we use a fast +non-cryptographic hash. + +This is the same as the algorithm used by Firefox -- which is a +homespun one not based on any widely-known algorithm -- though +modified to produce 64-bit hash values instead of 32-bit hash +values. It consistently out-performs an FNV-based hash within rustc +itself -- the collision rate is similar or slightly worse than FNV, +but the speed of the hash function itself is much higher because it +works on up to 8 bytes at a time. + +## Usage + +```rust +use rustc_hash::FxHashMap; + +let mut map: FxHashMap<u32, u32> = FxHashMap::default(); +map.insert(22, 44); +``` + +### `no_std` + +This crate can be used as a `no_std` crate by disabling the `std` +feature, which is on by default, as follows: + +```toml +rustc-hash = { version = "1.0", default-features = false } +``` + +In this configuration, `FxHasher` is the only export, and the +`FxHashMap`/`FxHashSet` type aliases are omitted. diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/src/lib.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/src/lib.rs new file mode 100644 index 0000000..ee9ad31 --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/src/lib.rs @@ -0,0 +1,148 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Fast, non-cryptographic hash used by rustc and Firefox. +//! +//! # Example +//! +//! ```rust +//! # #[cfg(feature = "std")] +//! # fn main() { +//! use rustc_hash::FxHashMap; +//! let mut map: FxHashMap<u32, u32> = FxHashMap::default(); +//! map.insert(22, 44); +//! # } +//! # #[cfg(not(feature = "std"))] +//! # fn main() { } +//! ``` + +#![no_std] + +#[cfg(feature = "std")] +extern crate std; + +use core::convert::TryInto; +use core::default::Default; +#[cfg(feature = "std")] +use core::hash::BuildHasherDefault; +use core::hash::Hasher; +use core::mem::size_of; +use core::ops::BitXor; +#[cfg(feature = "std")] +use std::collections::{HashMap, HashSet}; + +/// Type alias for a hashmap using the `fx` hash algorithm. +#[cfg(feature = "std")] +pub type FxHashMap<K, V> = HashMap<K, V, BuildHasherDefault<FxHasher>>; + +/// Type alias for a hashmap using the `fx` hash algorithm. +#[cfg(feature = "std")] +pub type FxHashSet<V> = HashSet<V, BuildHasherDefault<FxHasher>>; + +/// A speedy hash algorithm for use within rustc. The hashmap in liballoc +/// by default uses SipHash which isn't quite as speedy as we want. In the +/// compiler we're not really worried about DOS attempts, so we use a fast +/// non-cryptographic hash. +/// +/// This is the same as the algorithm used by Firefox -- which is a homespun +/// one not based on any widely-known algorithm -- though modified to produce +/// 64-bit hash values instead of 32-bit hash values. It consistently +/// out-performs an FNV-based hash within rustc itself -- the collision rate is +/// similar or slightly worse than FNV, but the speed of the hash function +/// itself is much higher because it works on up to 8 bytes at a time. +pub struct FxHasher { + hash: usize, +} + +#[cfg(target_pointer_width = "32")] +const K: usize = 0x9e3779b9; +#[cfg(target_pointer_width = "64")] +const K: usize = 0x517cc1b727220a95; + +impl Default for FxHasher { + #[inline] + fn default() -> FxHasher { + FxHasher { hash: 0 } + } +} + +impl FxHasher { + #[inline] + fn add_to_hash(&mut self, i: usize) { + self.hash = self.hash.rotate_left(5).bitxor(i).wrapping_mul(K); + } +} + +impl Hasher for FxHasher { + #[inline] + fn write(&mut self, mut bytes: &[u8]) { + #[cfg(target_pointer_width = "32")] + let read_usize = |bytes: &[u8]| u32::from_ne_bytes(bytes[..4].try_into().unwrap()); + #[cfg(target_pointer_width = "64")] + let read_usize = |bytes: &[u8]| u64::from_ne_bytes(bytes[..8].try_into().unwrap()); + + let mut hash = FxHasher { hash: self.hash }; + assert!(size_of::<usize>() <= 8); + while bytes.len() >= size_of::<usize>() { + hash.add_to_hash(read_usize(bytes) as usize); + bytes = &bytes[size_of::<usize>()..]; + } + if (size_of::<usize>() > 4) && (bytes.len() >= 4) { + hash.add_to_hash(u32::from_ne_bytes(bytes[..4].try_into().unwrap()) as usize); + bytes = &bytes[4..]; + } + if (size_of::<usize>() > 2) && bytes.len() >= 2 { + hash.add_to_hash(u16::from_ne_bytes(bytes[..2].try_into().unwrap()) as usize); + bytes = &bytes[2..]; + } + if (size_of::<usize>() > 1) && bytes.len() >= 1 { + hash.add_to_hash(bytes[0] as usize); + } + self.hash = hash.hash; + } + + #[inline] + fn write_u8(&mut self, i: u8) { + self.add_to_hash(i as usize); + } + + #[inline] + fn write_u16(&mut self, i: u16) { + self.add_to_hash(i as usize); + } + + #[inline] + fn write_u32(&mut self, i: u32) { + self.add_to_hash(i as usize); + } + + #[cfg(target_pointer_width = "32")] + #[inline] + fn write_u64(&mut self, i: u64) { + self.add_to_hash(i as usize); + self.add_to_hash((i >> 32) as usize); + } + + #[cfg(target_pointer_width = "64")] + #[inline] + fn write_u64(&mut self, i: u64) { + self.add_to_hash(i as usize); + } + + #[inline] + fn write_usize(&mut self, i: usize) { + self.add_to_hash(i); + } + + #[inline] + fn finish(&self) -> u64 { + self.hash as u64 + } +} diff --git a/gcc/rust/checks/errors/borrowck/polonius/rust-polonius.h b/gcc/rust/checks/errors/borrowck/polonius/rust-polonius.h index b013a93..0ce2142 100644 --- a/gcc/rust/checks/errors/borrowck/polonius/rust-polonius.h +++ b/gcc/rust/checks/errors/borrowck/polonius/rust-polonius.h @@ -35,7 +35,7 @@ struct FullPoint bool mid; /** Expands a compressed `Point` into its components. - * See `Point` docs for encoding details. + * See `Point` docs for encoding details in ./rust-polonius-ffi.h */ explicit FullPoint (Point point) : bb (extract_bb (point)), stmt (extract_stmt (point)), @@ -45,7 +45,24 @@ struct FullPoint static uint32_t extract_bb (Point point) { return point >> 16; } static uint32_t extract_stmt (Point point) { - return (point & ~(1 << 16)) >> 1; + // Point is a 32 bit unsigned integer + // 16 15 1 + // xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxx x + // ^~~~~~~~~~~~~~~~ ^~~~~~~~~~~~~~~ ^ + // | | | + // basic_block | start/mid + // statement + // the left most 16 bits store the basic block number + // the right most bit, represents the start/mid status + // the remaining 15 bits between these two represent the statement number + // which we need to extract in this fucntion + // + // firstly we can get rid of right most bit by performing left shift once + auto hide_left_most_bit = point >> 1; + // now we only need the 15 bits on the right + // we can mask the remaining bits by performing bitwise AND with fifteen + // 1's which in hexadecimal is 0x7FFF + return hide_left_most_bit & 0x7FFF; } static bool extract_mid (Point point) { return point & 1; } 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 index acfcdd8..6b8b2e9 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.cc +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.cc @@ -21,6 +21,7 @@ #include "rust-bir-builder-lazyboolexpr.h" #include "rust-bir-builder-pattern.h" #include "rust-bir-builder-struct.h" +#include "rust-hir-expr.h" namespace Rust { namespace BIR { @@ -44,7 +45,8 @@ ExprStmtBuilder::setup_loop (HIR::BaseLoopExpr &expr) BasicBlockId break_bb = new_bb (); // We are still outside the loop block; - ScopeId continue_scope = ctx.place_db.get_current_scope_id () + 1; + ScopeId continue_scope + = ctx.place_db.get_current_scope_id ().next_scope_id (); ctx.loop_and_label_stack.emplace_back (true, label, label_var, break_bb, continue_bb, continue_scope); @@ -80,14 +82,21 @@ ExprStmtBuilder::visit (HIR::ClosureExpr &expr) { auto closure_ty = lookup_type (expr)->as<TyTy::ClosureType> (); std::vector<PlaceId> captures; + std::vector<location_t> capture_locations; for (auto &capture : closure_ty->get_captures ()) { captures.push_back (ctx.place_db.lookup_variable (capture)); + auto location = Analysis::Mappings::get () + .lookup_ast_item (capture) + .value () + ->get_locus (); + capture_locations.push_back (location); } - move_all (captures); + move_all (captures, capture_locations); // Note: Not a coercion site for captures. - return_expr (new InitializerExpr (std::move (captures)), lookup_type (expr)); + return_expr (new InitializerExpr (std::move (captures)), lookup_type (expr), + expr.get_locus ()); } void @@ -96,46 +105,55 @@ ExprStmtBuilder::visit (HIR::StructExprStructFields &fields) auto *p_adt_type = lookup_type (fields)->as<TyTy::ADTType> (); auto struct_ty = p_adt_type->get_variants ().at (0); auto init_values = StructBuilder (ctx, struct_ty).build (fields); - move_all (init_values); + // collect fields locations + std::vector<location_t> field_locations; + for (auto &field : fields.get_fields ()) + { + field_locations.push_back (field->get_locus ()); + } + move_all (init_values, field_locations); return_expr (new InitializerExpr (std::move (init_values)), - lookup_type (fields)); + lookup_type (fields), fields.get_locus ()); } 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))); + return_place (ctx.place_db.get_constant (lookup_type (expr)), + expr.get_locus ()); } void ExprStmtBuilder::visit (HIR::LiteralExpr &expr) { // Different literal values of the same type are not distinguished in BIR. - return_place (ctx.place_db.get_constant (lookup_type (expr))); + return_place (ctx.place_db.get_constant (lookup_type (expr)), + expr.get_locus ()); } void ExprStmtBuilder::visit (HIR::BorrowExpr &expr) { - auto operand = visit_expr (*expr.get_expr ()); + auto operand = visit_expr (expr.get_expr ()); if (ctx.place_db[operand].is_constant ()) { // Cannot borrow a constant, must create a temporary copy. - push_tmp_assignment (operand); + push_tmp_assignment (operand, expr.get_locus ()); operand = translated; } // BorrowExpr cannot be annotated with lifetime. - return_borrowed (operand, lookup_type (expr)); + return_borrowed (operand, lookup_type (expr), expr.get_locus ()); } void ExprStmtBuilder::visit (HIR::DereferenceExpr &expr) { - auto operand = visit_expr (*expr.get_expr ()); + auto operand = visit_expr (expr.get_expr ()); return_place (ctx.place_db.lookup_or_add_path (Place::DEREF, - lookup_type (expr), operand)); + lookup_type (expr), operand), + expr.get_locus ()); } void @@ -148,26 +166,32 @@ ExprStmtBuilder::visit (HIR::ErrorPropagationExpr &expr) void ExprStmtBuilder::visit (HIR::NegationExpr &expr) { - PlaceId operand = visit_expr (*expr.get_expr ()); - return_expr (new Operator<1> ({move_place (operand)}), lookup_type (expr)); + PlaceId operand = visit_expr (expr.get_expr ()); + return_expr (new Operator<1> ( + {move_place (operand, expr.get_expr ().get_locus ())}), + lookup_type (expr), expr.get_locus ()); } 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> ({move_place (lhs), move_place (rhs)}), - lookup_type (expr)); + PlaceId lhs = visit_expr (expr.get_lhs ()); + PlaceId rhs = visit_expr (expr.get_rhs ()); + return_expr (new Operator<2> ( + {move_place (lhs, expr.get_lhs ().get_locus ()), + move_place (rhs, expr.get_rhs ().get_locus ())}), + lookup_type (expr), expr.get_locus ()); } 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> ({move_place (lhs), move_place (rhs)}), - lookup_type (expr)); + PlaceId lhs = visit_expr (expr.get_lhs ()); + PlaceId rhs = visit_expr (expr.get_rhs ()); + return_expr (new Operator<2> ( + {move_place (lhs, expr.get_lhs ().get_locus ()), + move_place (rhs, expr.get_rhs ().get_locus ())}), + lookup_type (expr), expr.get_locus ()); } void @@ -175,57 +199,66 @@ ExprStmtBuilder::visit (HIR::LazyBooleanExpr &expr) { return_place (LazyBooleanExprBuilder (ctx, take_or_create_return_place ( lookup_type (expr))) - .build (expr)); + .build (expr), + expr.get_locus ()); } void ExprStmtBuilder::visit (HIR::TypeCastExpr &expr) { - auto operand = visit_expr (*expr.get_expr ()); - return_expr (new Operator<1> ({operand}), lookup_type (expr)); + auto operand = visit_expr (expr.get_expr ()); + return_expr (new Operator<1> ({operand}), lookup_type (expr), + expr.get_locus ()); } void ExprStmtBuilder::visit (HIR::AssignmentExpr &expr) { - auto lhs = visit_expr (*expr.get_lhs ()); - auto rhs = visit_expr (*expr.get_rhs ()); - push_assignment (lhs, rhs); + auto lhs = visit_expr (expr.get_lhs ()); + auto rhs = visit_expr (expr.get_rhs ()); + push_assignment (lhs, rhs, expr.get_locus ()); translated = INVALID_PLACE; } 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})); + auto lhs = visit_expr (expr.get_lhs ()); + auto rhs = visit_expr (expr.get_rhs ()); + push_assignment (lhs, new Operator<2> ({lhs, rhs}), expr.get_locus ()); } void ExprStmtBuilder::visit (HIR::GroupedExpr &expr) { - return_place (visit_expr (*expr.get_expr_in_parens ())); + return_place (visit_expr (expr.get_expr_in_parens ()), expr.get_locus ()); } void ExprStmtBuilder::visit (HIR::ArrayExpr &expr) { auto &elems = expr.get_internal_elements (); - switch (elems->get_array_expr_type ()) + switch (elems.get_array_expr_type ()) { case HIR::ArrayElems::VALUES: { - auto &elem_vals = (static_cast<HIR::ArrayElemsValues &> (*elems)); + auto &elem_vals = (static_cast<HIR::ArrayElemsValues &> (elems)); auto init_values = visit_list (elem_vals.get_values ()); - move_all (init_values); + // collect locations + std::vector<location_t> value_locations; + for (auto &value : elem_vals.get_values ()) + { + value_locations.push_back (value->get_locus ()); + } + move_all (init_values, value_locations); return_expr (new InitializerExpr (std::move (init_values)), - lookup_type (expr)); + lookup_type (expr), expr.get_locus ()); break; } case HIR::ArrayElems::COPIED: { - auto &elem_copied = (static_cast<HIR::ArrayElemsCopied &> (*elems)); - auto init = visit_expr (*elem_copied.get_elem_to_copy ()); - return_expr (new InitializerExpr ({init}), lookup_type (expr)); + auto &elem_copied = (static_cast<HIR::ArrayElemsCopied &> (elems)); + auto init = visit_expr (elem_copied.get_elem_to_copy ()); + return_expr (new InitializerExpr ({init}), lookup_type (expr), + expr.get_locus ()); break; } } @@ -234,12 +267,13 @@ ExprStmtBuilder::visit (HIR::ArrayExpr &expr) void ExprStmtBuilder::visit (HIR::ArrayIndexExpr &expr) { - auto lhs = visit_expr (*expr.get_array_expr ()); - auto rhs = visit_expr (*expr.get_index_expr ()); + auto lhs = visit_expr (expr.get_array_expr ()); + auto rhs = visit_expr (expr.get_index_expr ()); // The index is not tracked in BIR. std::ignore = rhs; - return_place ( - ctx.place_db.lookup_or_add_path (Place::INDEX, lookup_type (expr), lhs)); + return_place (ctx.place_db.lookup_or_add_path (Place::INDEX, + lookup_type (expr), lhs), + expr.get_locus ()); } void @@ -247,22 +281,23 @@ ExprStmtBuilder::visit (HIR::TupleExpr &expr) { std::vector<PlaceId> init_values = visit_list (expr.get_tuple_elems ()); return_expr (new InitializerExpr (std::move (init_values)), - lookup_type (expr)); + lookup_type (expr), expr.get_locus ()); } void ExprStmtBuilder::visit (HIR::TupleIndexExpr &expr) { - auto tuple = visit_expr (*expr.get_tuple_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 ())); + expr.get_tuple_index ()), + expr.get_locus ()); } void ExprStmtBuilder::visit (HIR::CallExpr &expr) { - PlaceId fn = visit_expr (*expr.get_fnexpr ()); + PlaceId fn = visit_expr (expr.get_fnexpr ()); std::vector<PlaceId> arguments = visit_list (expr.get_arguments ()); const auto fn_type @@ -273,20 +308,34 @@ ExprStmtBuilder::visit (HIR::CallExpr &expr) coercion_site (arguments[i], fn_type->get_param_type_at (i)); } - move_all (arguments); + // collect parameter locations + std::vector<location_t> parameter_locations; + for (auto ¶meter : expr.get_arguments ()) + { + parameter_locations.push_back (parameter->get_locus ()); + } + move_all (arguments, parameter_locations); return_expr (new CallExpr (fn, std::move (arguments)), lookup_type (expr), - true); + expr.get_locus (), true); } void +ExprStmtBuilder::visit (HIR::InlineAsm &expr) +{} + +void +ExprStmtBuilder::visit (HIR::LlvmInlineAsm &expr) +{} + +void ExprStmtBuilder::visit (HIR::MethodCallExpr &expr) {} void ExprStmtBuilder::visit (HIR::FieldAccessExpr &expr) { - auto receiver = visit_expr (*expr.get_receiver_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> (); @@ -302,7 +351,8 @@ ExprStmtBuilder::visit (HIR::FieldAccessExpr &expr) return_place (ctx.place_db.lookup_or_add_path (Place::FIELD, field_ty->get_field_type (), - receiver, field_index)); + receiver, field_index), + expr.get_locus ()); } void @@ -338,7 +388,8 @@ ExprStmtBuilder::visit (HIR::BlockExpr &block) if (block.has_expr () && !unreachable) { push_assignment (block_ctx.label_var, - visit_expr (*block.get_final_expr ())); + visit_expr (block.get_final_expr ()), + block.get_start_locus ()); } if (!ctx.get_current_bb ().is_terminated ()) { @@ -347,13 +398,14 @@ ExprStmtBuilder::visit (HIR::BlockExpr &block) ctx.current_bb = block_ctx.break_bb; ctx.loop_and_label_stack.pop_back (); - return_place (block_ctx.label_var); + return_place (block_ctx.label_var, block.get_start_locus ()); } else if (block.has_expr () && !unreachable) { - return_place (visit_expr (*block.get_final_expr (), + return_place (visit_expr (block.get_final_expr (), take_or_create_return_place ( - lookup_type (*block.get_final_expr ())))); + lookup_type (block.get_final_expr ()))), + block.get_start_locus ()); } if (!unreachable) @@ -368,7 +420,7 @@ ExprStmtBuilder::visit (HIR::ContinueExpr &cont) LoopAndLabelCtx info = cont.has_label () ? get_label_ctx (cont.get_label ()) : get_unnamed_loop_ctx (); start_new_consecutive_bb (); - unwind_until (info.continue_bb); + unwind_until (info.continue_scope); push_goto (info.continue_bb); // No code allowed after continue. Handled in BlockExpr. } @@ -379,7 +431,8 @@ ExprStmtBuilder::visit (HIR::BreakExpr &brk) LoopAndLabelCtx info = brk.has_label () ? get_label_ctx (brk.get_label ()) : get_unnamed_loop_ctx (); if (brk.has_break_expr ()) - push_assignment (info.label_var, visit_expr (*brk.get_expr ())); + push_assignment (info.label_var, visit_expr (brk.get_expr ()), + brk.get_locus ()); start_new_consecutive_bb (); unwind_until (ctx.place_db.get_scope (info.continue_scope).parent); @@ -390,44 +443,49 @@ ExprStmtBuilder::visit (HIR::BreakExpr &brk) 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)); + 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), + range.get_locus ()); } void ExprStmtBuilder::visit (HIR::RangeFromExpr &expr) { - auto from = visit_expr (*expr.get_from_expr ()); - return_expr (new InitializerExpr ({from}), lookup_type (expr)); + auto from = visit_expr (expr.get_from_expr ()); + return_expr (new InitializerExpr ({from}), lookup_type (expr), + expr.get_locus ()); } void ExprStmtBuilder::visit (HIR::RangeToExpr &expr) { - auto to = visit_expr (*expr.get_to_expr ()); - return_expr (new InitializerExpr ({to}), lookup_type (expr)); + auto to = visit_expr (expr.get_to_expr ()); + return_expr (new InitializerExpr ({to}), lookup_type (expr), + expr.get_locus ()); } void ExprStmtBuilder::visit (HIR::RangeFullExpr &expr) { - return_expr (new InitializerExpr ({}), lookup_type (expr)); + return_expr (new InitializerExpr ({}), lookup_type (expr), expr.get_locus ()); } 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)); + 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), + expr.get_locus ()); } void ExprStmtBuilder::visit (HIR::RangeToInclExpr &expr) { - auto to = visit_expr (*expr.get_to_expr ()); - return_expr (new InitializerExpr ({to}), lookup_type (expr)); + auto to = visit_expr (expr.get_to_expr ()); + return_expr (new InitializerExpr ({to}), lookup_type (expr), + expr.get_locus ()); } void @@ -436,10 +494,12 @@ ExprStmtBuilder::visit (HIR::ReturnExpr &ret) if (ret.has_return_expr ()) { push_assignment (RETURN_VALUE_PLACE, - move_place (visit_expr (*ret.get_expr ()))); + move_place (visit_expr (ret.get_expr ()), + ret.get_expr ().get_locus ()), + ret.get_expr ().get_locus ()); } unwind_until (ROOT_SCOPE); - ctx.get_current_bb ().statements.emplace_back (Statement::Kind::RETURN); + push_return (ret.get_locus ()); translated = INVALID_PLACE; } @@ -454,7 +514,7 @@ ExprStmtBuilder::visit (HIR::LoopExpr &expr) { auto loop = setup_loop (expr); - std::ignore = visit_expr (*expr.get_loop_block ()); + std::ignore = visit_expr (expr.get_loop_block ()); if (!ctx.get_current_bb ().is_terminated ()) push_goto (loop.continue_bb); @@ -466,12 +526,12 @@ ExprStmtBuilder::visit (HIR::WhileLoopExpr &expr) { auto loop = setup_loop (expr); - auto cond_val = visit_expr (*expr.get_predicate_expr ()); + auto cond_val = visit_expr (expr.get_predicate_expr ()); auto body_bb = new_bb (); - push_switch (cond_val, {body_bb, loop.break_bb}); + push_switch (cond_val, expr.get_locus (), {body_bb, loop.break_bb}); ctx.current_bb = body_bb; - std::ignore = visit_expr (*expr.get_loop_block ()); + std::ignore = visit_expr (expr.get_loop_block ()); push_goto (loop.continue_bb); ctx.current_bb = loop.break_bb; @@ -489,15 +549,15 @@ ExprStmtBuilder::visit (HIR::IfExpr &expr) { // If without else cannot return a non-unit value (see [E0317]). - if (expr.get_if_block ()->statements.empty ()) + if (expr.get_if_block ().statements.empty ()) return; - push_switch (visit_expr (*expr.get_if_condition ())); + push_switch (visit_expr (expr.get_if_condition ()), expr.get_locus ()); BasicBlockId if_block = ctx.current_bb; ctx.current_bb = new_bb (); BasicBlockId then_start_block = ctx.current_bb; - std::ignore = visit_expr (*expr.get_if_block ()); + std::ignore = visit_expr (expr.get_if_block ()); if (!ctx.get_current_bb ().is_terminated ()) push_goto (INVALID_BB); // Resolved later. BasicBlockId then_end_block = ctx.current_bb; @@ -518,28 +578,30 @@ ExprStmtBuilder::visit (HIR::IfExpr &expr) void ExprStmtBuilder::visit (HIR::IfExprConseqElse &expr) { - push_switch (move_place (visit_expr (*expr.get_if_condition ()))); + push_switch (move_place (visit_expr (expr.get_if_condition ()), + expr.get_if_condition ().get_locus ()), + expr.get_locus ()); BasicBlockId if_end_bb = ctx.current_bb; PlaceId result = take_or_create_return_place (lookup_type (expr)); ctx.current_bb = new_bb (); BasicBlockId then_start_bb = ctx.current_bb; - std::ignore = visit_expr (*expr.get_if_block (), result); + std::ignore = visit_expr (expr.get_if_block (), result); if (!ctx.get_current_bb ().is_terminated ()) push_goto (INVALID_BB); // Resolved later. BasicBlockId then_end_bb = ctx.current_bb; ctx.current_bb = new_bb (); BasicBlockId else_start_bb = ctx.current_bb; - std::ignore = visit_expr (*expr.get_else_block (), result); + std::ignore = visit_expr (expr.get_else_block (), result); if (!ctx.get_current_bb ().is_terminated ()) push_goto (INVALID_BB); // Resolved later. BasicBlockId else_end_bb = ctx.current_bb; ctx.current_bb = new_bb (); BasicBlockId final_start_bb = ctx.current_bb; - return_place (result); + return_place (result, expr.get_locus ()); // Jumps are added at the end to match rustc MIR order for easier comparison. add_jump (if_end_bb, then_start_bb); @@ -555,18 +617,6 @@ ExprStmtBuilder::visit (HIR::IfExprConseqElse &expr) } 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) { rust_sorry_at (expr.get_locus (), "match expressions are not supported"); @@ -627,7 +677,7 @@ ExprStmtBuilder::visit (HIR::QualifiedPathInExpression &expr) { // Note: Type is only stored for the expr, not the segment. PlaceId result = resolve_variable_or_fn (expr, lookup_type (expr)); - return_place (result); + return_place (result, expr.get_locus ()); } void @@ -635,7 +685,7 @@ ExprStmtBuilder::visit (HIR::PathInExpression &expr) { // Note: Type is only stored for the expr, not the segment. PlaceId result = resolve_variable_or_fn (expr, lookup_type (expr)); - return_place (result); + return_place (result, expr.get_locus ()); } void @@ -645,39 +695,39 @@ ExprStmtBuilder::visit (HIR::LetStmt &stmt) tl::optional<TyTy::BaseType *> type_annotation; if (stmt.has_type ()) - type_annotation = lookup_type (*stmt.get_type ()); + type_annotation = lookup_type (stmt.get_type ()); - if (stmt.get_pattern ()->get_pattern_type () == HIR::Pattern::IDENTIFIER) + if (stmt.get_pattern ().get_pattern_type () == HIR::Pattern::IDENTIFIER) { // Only if a pattern is just an identifier, no destructuring is needed. // Hoverer PatternBindingBuilder cannot change existing temporary // (init expr is evaluated before pattern binding) into a // variable, so it would emit extra assignment. - auto var = declare_variable (stmt.get_pattern ()->get_mappings ()); + auto var = declare_variable (stmt.get_pattern ().get_mappings ()); if (stmt.has_type ()) - push_user_type_ascription (var, lookup_type (*stmt.get_type ())); + push_user_type_ascription (var, lookup_type (stmt.get_type ())); if (stmt.has_init_expr ()) - std::ignore = visit_expr (*stmt.get_init_expr (), var); + std::ignore = visit_expr (stmt.get_init_expr (), var); } else { if (stmt.has_init_expr ()) - init = visit_expr (*stmt.get_init_expr ()); + init = visit_expr (stmt.get_init_expr ()); PatternBindingBuilder (ctx, init, type_annotation) - .go (*stmt.get_pattern ()); + .go (stmt.get_pattern ()); } } void ExprStmtBuilder::visit (HIR::ExprStmt &stmt) { - PlaceId result = visit_expr (*stmt.get_expr ()); + PlaceId result = visit_expr (stmt.get_expr ()); // We must read the value for current liveness and we must not store it into // the same place. if (result != INVALID_PLACE) - push_tmp_assignment (result); + push_tmp_assignment (result, stmt.get_locus ()); } } // namespace BIR } // namespace Rust 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 index 3a58611..5cab3c4 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.h +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.h @@ -99,9 +99,9 @@ protected: // Expr void visit (HIR::WhileLetLoopExpr &expr) override; void visit (HIR::IfExpr &expr) override; void visit (HIR::IfExprConseqElse &expr) override; + void visit (HIR::InlineAsm &expr) override; + void visit (HIR::LlvmInlineAsm &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; diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-internal.h b/gcc/rust/checks/errors/borrowck/rust-bir-builder-internal.h index f47c41f..4df0e14 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-internal.h +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-internal.h @@ -76,8 +76,8 @@ struct BuilderContext Resolver::Resolver &resolver; // BIR output - std::vector<BasicBlock> basic_blocks; - size_t current_bb = 0; + BasicBlocks basic_blocks; + BasicBlockId current_bb = ENTRY_BASIC_BLOCK; /** * Allocation and lookup of places (variables, temporaries, paths, and @@ -156,7 +156,7 @@ protected: auto place_id = ctx.place_db.add_variable (nodeid, ty); - if (ctx.place_db.get_current_scope_id () != 0) + if (ctx.place_db.get_current_scope_id () != INVALID_SCOPE) push_storage_live (place_id); if (user_type_annotation) @@ -170,7 +170,7 @@ protected: void pop_scope () { auto &scope = ctx.place_db.get_current_scope (); - if (ctx.place_db.get_current_scope_id () != 0) + if (ctx.place_db.get_current_scope_id () != INVALID_SCOPE) { std::for_each (scope.locals.rbegin (), scope.locals.rend (), [&] (PlaceId place) { push_storage_dead (place); }); @@ -206,7 +206,7 @@ protected: FreeRegions bind_regions (std::vector<TyTy::Region> regions, FreeRegions parent_free_regions) { - std::vector<FreeRegion> free_regions; + FreeRegions free_regions; for (auto ®ion : regions) { if (region.is_early_bound ()) @@ -215,7 +215,7 @@ protected: } else if (region.is_static ()) { - free_regions.push_back (0); + free_regions.push_back (STATIC_FREE_REGION); } else if (region.is_anonymous ()) { @@ -231,87 +231,95 @@ protected: rust_unreachable (); } } - // This is necesarry because of clash of current gcc and gcc4.8. - FreeRegions free_regions_final{std::move (free_regions)}; - return free_regions_final; + return free_regions; } protected: // Helpers to add BIR statements - void push_assignment (PlaceId lhs, AbstractExpr *rhs) + void push_assignment (PlaceId lhs, AbstractExpr *rhs, location_t location) { - ctx.get_current_bb ().statements.emplace_back (lhs, rhs); + ctx.get_current_bb ().statements.push_back ( + Statement::make_assignment (lhs, rhs, location)); translated = lhs; } - void push_assignment (PlaceId lhs, PlaceId rhs) + void push_assignment (PlaceId lhs, PlaceId rhs, location_t location) { - push_assignment (lhs, new Assignment (rhs)); + push_assignment (lhs, new Assignment (rhs), location); } - void push_tmp_assignment (AbstractExpr *rhs, TyTy::BaseType *tyty) + void push_tmp_assignment (AbstractExpr *rhs, TyTy::BaseType *tyty, + location_t location) { PlaceId tmp = ctx.place_db.add_temporary (tyty); push_storage_live (tmp); - push_assignment (tmp, rhs); + push_assignment (tmp, rhs, location); } - void push_tmp_assignment (PlaceId rhs) + void push_tmp_assignment (PlaceId rhs, location_t location) { - push_tmp_assignment (new Assignment (rhs), ctx.place_db[rhs].tyty); + push_tmp_assignment (new Assignment (rhs), ctx.place_db[rhs].tyty, + location); } - void push_switch (PlaceId switch_val, + void push_switch (PlaceId switch_val, location_t location, std::initializer_list<BasicBlockId> destinations = {}) { - auto copy = move_place (switch_val); - ctx.get_current_bb ().statements.emplace_back (Statement::Kind::SWITCH, - copy); + auto copy = move_place (switch_val, location); + ctx.get_current_bb ().statements.push_back (Statement::make_switch (copy)); ctx.get_current_bb ().successors.insert ( ctx.get_current_bb ().successors.end (), destinations); } void push_goto (BasicBlockId bb) { - ctx.get_current_bb ().statements.emplace_back (Statement::Kind::GOTO); + ctx.get_current_bb ().statements.push_back (Statement::make_goto ()); if (bb != INVALID_BB) // INVALID_BB means the goto will be resolved later. ctx.get_current_bb ().successors.push_back (bb); } void push_storage_live (PlaceId place) { - ctx.get_current_bb ().statements.emplace_back ( - Statement::Kind::STORAGE_LIVE, place); + ctx.get_current_bb ().statements.push_back ( + Statement::make_storage_live (place)); } void push_storage_dead (PlaceId place) { - ctx.get_current_bb ().statements.emplace_back ( - Statement::Kind::STORAGE_DEAD, place); + ctx.get_current_bb ().statements.push_back ( + Statement::make_storage_dead (place)); } void push_user_type_ascription (PlaceId place, TyTy::BaseType *ty) { - ctx.get_current_bb ().statements.emplace_back ( - Statement::Kind::USER_TYPE_ASCRIPTION, place, ty); + ctx.get_current_bb ().statements.push_back ( + Statement::make_user_type_ascription (place, ty)); } void push_fake_read (PlaceId place) { - ctx.get_current_bb ().statements.emplace_back (Statement::Kind::FAKE_READ, - place); + ctx.get_current_bb ().statements.push_back ( + Statement::make_fake_read (place)); } - PlaceId borrow_place (PlaceId place_id, TyTy::BaseType *ty) + void push_return (location_t location) + { + ctx.get_current_bb ().statements.push_back ( + Statement::make_return (location)); + } + + PlaceId borrow_place (PlaceId place_id, TyTy::BaseType *ty, + location_t location) { auto mutability = ty->as<const TyTy::ReferenceType> ()->mutability (); - auto loan = ctx.place_db.add_loan ({mutability, place_id}); - push_tmp_assignment (new BorrowExpr (place_id, loan, - ctx.place_db.get_next_free_region ()), - ty); + auto loan = ctx.place_db.add_loan ({mutability, place_id, location}); + push_tmp_assignment ( + new BorrowExpr (place_id, loan, + ctx.place_db.get_next_free_region ().value), + ty, location); return translated; } - PlaceId move_place (PlaceId arg) + PlaceId move_place (PlaceId arg, location_t location) { auto &place = ctx.place_db[arg]; @@ -319,34 +327,38 @@ protected: // Helpers to add BIR statements return arg; if (place.tyty->is<TyTy::ReferenceType> ()) - return reborrow_place (arg); + return reborrow_place (arg, location); if (place.is_rvalue ()) return arg; - push_tmp_assignment (arg); + push_tmp_assignment (arg, location); return translated; } - PlaceId reborrow_place (PlaceId arg) + PlaceId reborrow_place (PlaceId arg, location_t location) { auto ty = ctx.place_db[arg].tyty->as<TyTy::ReferenceType> (); return borrow_place (ctx.place_db.lookup_or_add_path (Place::DEREF, ty->get_base (), arg), - ty); + ty, location); } - template <typename T> void move_all (T &args) + template <typename T> + void move_all (T &args, std::vector<location_t> locations) { - std::transform (args.begin (), args.end (), args.begin (), - [this] (PlaceId arg) { return move_place (arg); }); + rust_assert (args.size () == locations.size ()); + std::transform (args.begin (), args.end (), locations.begin (), + args.begin (), [this] (PlaceId arg, location_t location) { + return move_place (arg, location); + }); } protected: // CFG helpers BasicBlockId new_bb () { ctx.basic_blocks.emplace_back (); - return ctx.basic_blocks.size () - 1; + return {ctx.basic_blocks.size () - 1}; } BasicBlockId start_new_consecutive_bb () @@ -477,12 +489,15 @@ protected: // Implicit conversions. { if (ctx.place_db[translated].tyty->get_kind () != TyTy::REF) { + // FIXME: not sure how to fetch correct location for this + // this function is unused yet, so can ignore for now auto ty = ctx.place_db[translated].tyty; translated = borrow_place (translated, new TyTy::ReferenceType (ty->get_ref (), TyTy::TyVar (ty->get_ref ()), - Mutability::Imm)); + Mutability::Imm), + UNKNOWN_LOCATION); } } }; @@ -531,16 +546,16 @@ protected: * @param can_panic mark that expression can panic to insert jump to * cleanup. */ - void return_expr (AbstractExpr *expr, TyTy::BaseType *ty, + void return_expr (AbstractExpr *expr, TyTy::BaseType *ty, location_t location, bool can_panic = false) { if (expr_return_place != INVALID_PLACE) { - push_assignment (expr_return_place, expr); + push_assignment (expr_return_place, expr, location); } else { - push_tmp_assignment (expr, ty); + push_tmp_assignment (expr, ty, location); } if (can_panic) @@ -556,12 +571,12 @@ protected: } /** Mark place to be a result of processed subexpression. */ - void return_place (PlaceId place, bool can_panic = false) + void return_place (PlaceId place, location_t location, bool can_panic = false) { if (expr_return_place != INVALID_PLACE) { // Return place is already allocated, no need to defer assignment. - push_assignment (expr_return_place, place); + push_assignment (expr_return_place, place, location); } else { @@ -585,14 +600,16 @@ protected: translated = ctx.place_db.get_constant (lookup_type (expr)); } - PlaceId return_borrowed (PlaceId place_id, TyTy::BaseType *ty) + PlaceId return_borrowed (PlaceId place_id, TyTy::BaseType *ty, + location_t location) { // TODO: deduplicate with borrow_place auto loan = ctx.place_db.add_loan ( - {ty->as<const TyTy::ReferenceType> ()->mutability (), place_id}); + {ty->as<const TyTy::ReferenceType> ()->mutability (), place_id, + location}); return_expr (new BorrowExpr (place_id, loan, - ctx.place_db.get_next_free_region ()), - ty); + ctx.place_db.get_next_free_region ().value), + ty, location); return translated; } diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h b/gcc/rust/checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h index 11134c2..b7a1555 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h @@ -37,7 +37,8 @@ class LazyBooleanExprBuilder : public AbstractExprBuilder public: explicit LazyBooleanExprBuilder (BuilderContext &ctx, PlaceId expr_return_place = INVALID_PLACE) - : AbstractExprBuilder (ctx, expr_return_place), short_circuit_bb (0) + : AbstractExprBuilder (ctx, expr_return_place), + short_circuit_bb (ENTRY_BASIC_BLOCK) {} PlaceId build (HIR::LazyBooleanExpr &expr) @@ -45,13 +46,14 @@ public: PlaceId return_place = take_or_create_return_place (lookup_type (expr)); short_circuit_bb = new_bb (); - push_assignment (return_place, visit_expr (expr)); + push_assignment (return_place, visit_expr (expr), expr.get_locus ()); auto final_bb = new_bb (); push_goto (final_bb); ctx.current_bb = short_circuit_bb; push_assignment (return_place, - ctx.place_db.get_constant (lookup_type (expr))); + ctx.place_db.get_constant (lookup_type (expr)), + expr.get_locus ()); push_goto (final_bb); ctx.current_bb = final_bb; @@ -61,30 +63,31 @@ public: protected: void visit (HIR::LazyBooleanExpr &expr) override { - auto lhs = visit_expr (*expr.get_lhs ()); - push_switch (move_place (lhs), {short_circuit_bb}); + auto lhs = visit_expr (expr.get_lhs ()); + push_switch (move_place (lhs, expr.get_lhs ().get_locus ()), + expr.get_locus (), {short_circuit_bb}); start_new_consecutive_bb (); - return_place (visit_expr (*expr.get_rhs ())); + return_place (visit_expr (expr.get_rhs ()), expr.get_locus ()); } void visit (HIR::GroupedExpr &expr) override { - expr.get_expr_in_parens ()->accept_vis (*this); + expr.get_expr_in_parens ().accept_vis (*this); } protected: public: void visit (HIR::QualifiedPathInExpression &expr) override { - return_place (ExprStmtBuilder (ctx).build (expr)); + return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ()); } void visit (HIR::PathInExpression &expr) override { - return_place (ExprStmtBuilder (ctx).build (expr)); + return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ()); } void visit (HIR::ClosureExpr &expr) override { - return_place (ExprStmtBuilder (ctx).build (expr)); + return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ()); } void visit (HIR::StructExprStructFields &fields) override { @@ -96,121 +99,116 @@ public: } void visit (HIR::LiteralExpr &expr) override { - return_place (ExprStmtBuilder (ctx).build (expr)); + return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ()); } void visit (HIR::BorrowExpr &expr) override { - return_place (ExprStmtBuilder (ctx).build (expr)); + return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ()); } void visit (HIR::DereferenceExpr &expr) override { - return_place (ExprStmtBuilder (ctx).build (expr)); + return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ()); } void visit (HIR::ErrorPropagationExpr &expr) override { - return_place (ExprStmtBuilder (ctx).build (expr)); + return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ()); } void visit (HIR::NegationExpr &expr) override { - return_place (ExprStmtBuilder (ctx).build (expr)); + return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ()); } void visit (HIR::ArithmeticOrLogicalExpr &expr) override { - return_place (ExprStmtBuilder (ctx).build (expr)); + return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ()); } void visit (HIR::ComparisonExpr &expr) override { - return_place (ExprStmtBuilder (ctx).build (expr)); + return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ()); } void visit (HIR::TypeCastExpr &expr) override { - return_place (ExprStmtBuilder (ctx).build (expr)); + return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ()); } void visit (HIR::AssignmentExpr &expr) override { - return_place (ExprStmtBuilder (ctx).build (expr)); + return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ()); } void visit (HIR::CompoundAssignmentExpr &expr) override { - return_place (ExprStmtBuilder (ctx).build (expr)); + return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ()); } void visit (HIR::ArrayExpr &expr) override { - return_place (ExprStmtBuilder (ctx).build (expr)); + return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ()); } void visit (HIR::ArrayIndexExpr &expr) override { - return_place (ExprStmtBuilder (ctx).build (expr)); + return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ()); } void visit (HIR::TupleExpr &expr) override { - return_place (ExprStmtBuilder (ctx).build (expr)); + return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ()); } void visit (HIR::TupleIndexExpr &expr) override { - return_place (ExprStmtBuilder (ctx).build (expr)); + return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ()); } void visit (HIR::CallExpr &expr) override { - return_place (ExprStmtBuilder (ctx).build (expr)); + return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ()); } void visit (HIR::MethodCallExpr &expr) override { - return_place (ExprStmtBuilder (ctx).build (expr)); + return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ()); } void visit (HIR::FieldAccessExpr &expr) override { - return_place (ExprStmtBuilder (ctx).build (expr)); + return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ()); } void visit (HIR::BlockExpr &expr) override { - return_place (ExprStmtBuilder (ctx).build (expr)); + return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ()); } void visit (HIR::UnsafeBlockExpr &expr) override { - return_place (ExprStmtBuilder (ctx).build (expr)); + return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ()); } void visit (HIR::LoopExpr &expr) override { - return_place (ExprStmtBuilder (ctx).build (expr)); + return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ()); } void visit (HIR::WhileLoopExpr &expr) override { - return_place (ExprStmtBuilder (ctx).build (expr)); + return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ()); } void visit (HIR::WhileLetLoopExpr &expr) override { - return_place (ExprStmtBuilder (ctx).build (expr)); + return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ()); } void visit (HIR::IfExpr &expr) override { - return_place (ExprStmtBuilder (ctx).build (expr)); + return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ()); } void visit (HIR::IfExprConseqElse &expr) override { - return_place (ExprStmtBuilder (ctx).build (expr)); - } - void visit (HIR::IfLetExpr &expr) override - { - return_place (ExprStmtBuilder (ctx).build (expr)); - } - void visit (HIR::IfLetExprConseqElse &expr) override - { - return_place (ExprStmtBuilder (ctx).build (expr)); + return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ()); } void visit (HIR::MatchExpr &expr) override { - return_place (ExprStmtBuilder (ctx).build (expr)); + return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ()); } void visit (HIR::AwaitExpr &expr) override { - return_place (ExprStmtBuilder (ctx).build (expr)); + return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ()); } void visit (HIR::AsyncBlockExpr &expr) override { - return_place (ExprStmtBuilder (ctx).build (expr)); + return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ()); } + void visit (HIR::InlineAsm &expr) override {} + void visit (HIR::LlvmInlineAsm &expr) override {} + protected: // Illegal at this position. void visit (HIR::StructExprFieldIdentifier &field) override { diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.cc b/gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.cc new file mode 100644 index 0000000..ee37bb0 --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.cc @@ -0,0 +1,273 @@ +#include "rust-bir-builder-pattern.h" + +namespace Rust { +namespace BIR { + +void +PatternBindingBuilder::visit_identifier (const Analysis::NodeMapping &node, + bool is_ref, location_t location, + bool is_mut) +{ + if (is_ref) + { + translated = declare_variable ( + node, + new TyTy::ReferenceType (node.get_hirid (), + TyTy::TyVar (node.get_hirid ()), + (is_mut) ? Mutability::Mut : Mutability::Imm)); + } + else + { + translated = declare_variable (node); + } + + if (init.has_value ()) + { + push_assignment (translated, init.value (), location); + } +} + +void +PatternBindingBuilder::visit (HIR::IdentifierPattern &pattern) +{ + // Top-level identifiers are resolved directly to avoid useless temporary + // (for cleaner BIR). + visit_identifier (pattern.get_mappings (), pattern.get_is_ref (), + pattern.get_locus (), pattern.is_mut ()); +} + +void +PatternBindingBuilder::visit (HIR::ReferencePattern &pattern) +{ + SavedState saved (this); + + init = init.map ([&] (PlaceId id) { + return ctx.place_db.lookup_or_add_path (Place::DEREF, lookup_type (pattern), + id); + }); + + type_annotation = type_annotation.map ([&] (TyTy::BaseType *ty) { + return ty->as<TyTy::ReferenceType> ()->get_base (); + }); + + pattern.get_referenced_pattern ().accept_vis (*this); +} + +void +PatternBindingBuilder::visit (HIR::SlicePattern &pattern) +{ + SavedState saved (this); + + // 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); + init = init.map ([&] (PlaceId id) { + return ctx.place_db.lookup_or_add_path (Place::INDEX, lookup_type (pattern), + id); + }); + + type_annotation = type_annotation.map ([&] (TyTy::BaseType *ty) { + return ty->as<TyTy::SliceType> ()->get_element_type (); + }); + + // Regions are unchnaged. + + for (auto &item : pattern.get_items ()) + { + item->accept_vis (*this); + } +} + +void +PatternBindingBuilder::visit (HIR::AltPattern &pattern) +{ + rust_sorry_at (pattern.get_locus (), + "borrow-checking of alt patterns is not yet implemented"); +} + +void +PatternBindingBuilder::visit (HIR::StructPattern &pattern) +{ + SavedState saved (this); + + auto tyty = ctx.place_db[init.value ()].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); + + 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 = init.map ([&] (PlaceId id) { + return ctx.place_db.lookup_or_add_path ( + Place::FIELD, lookup_type (tuple->get_tuple_pattern ()), id, + tuple->get_index ()); + }); + + type_annotation = type_annotation.map ([&] (TyTy::BaseType *ty) { + return ty->as<TyTy::ADTType> () + ->get_variants () + .at (0) + ->get_fields () + .at (tuple->get_index ()) + ->get_field_type (); + }); + + 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.value (), + 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.value (), + field_index); + visit_identifier (ident_field->get_mappings (), + ident_field->get_has_ref (), + ident_field->get_locus (), + ident_field->is_mut ()); + break; + } + } + } +} + +void +PatternBindingBuilder::visit_tuple_fields ( + std::vector<std::unique_ptr<HIR::Pattern>> &fields, SavedState &saved, + size_t &index) +{ + for (auto &item : fields) + { + auto type = lookup_type (*item); + + init = init.map ([&] (PlaceId id) { + return ctx.place_db.lookup_or_add_path (Place::FIELD, type, id, index); + }); + + type_annotation = type_annotation.map ([&] (TyTy::BaseType *ty) { + return ty->as<TyTy::TupleType> ()->get_fields ().at (index).get_tyty (); + }); + + regions = regions.map ([&] (FreeRegions regs) { + return bind_regions (Resolver::TypeCheckContext::get () + ->get_variance_analysis_ctx () + .query_type_regions (type), + regs); + }); + + item->accept_vis (*this); + index++; + } +} + +void +PatternBindingBuilder::visit (HIR::TuplePattern &pattern) +{ + 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.value ()].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 +PatternBindingBuilder::visit (HIR::TupleStructPattern &pattern) +{ + SavedState saved (this); + + type_annotation = tl::nullopt; + + auto type = lookup_type (pattern); + + regions = regions.map ([&] (FreeRegions regs) { + return bind_regions (Resolver::TypeCheckContext::get () + ->get_variance_analysis_ctx () + .query_type_regions (type), + regs); + }); + + size_t index = 0; + switch (pattern.get_items ().get_item_type ()) + { + case HIR::TupleStructItems::RANGED: { + auto &items + = static_cast<HIR::TupleStructItemsRange &> (pattern.get_items ()); + + rust_assert (type->get_kind () == TyTy::ADT); + auto adt_ty = static_cast<TyTy::ADTType *> (type); + 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::MULTIPLE: { + auto &items + = static_cast<HIR::TupleStructItemsNoRange &> (pattern.get_items ()); + visit_tuple_fields (items.get_patterns (), saved, index); + break; + } + } +} +} // namespace BIR +} // namespace Rust diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.h b/gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.h index f704f77..33ecd23 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.h +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.h @@ -65,265 +65,24 @@ public: void go (HIR::Pattern &pattern) { pattern.accept_vis (*this); } void visit_identifier (const Analysis::NodeMapping &node, bool is_ref, - bool is_mut = false) - { - if (is_ref) - { - translated = declare_variable ( - node, new TyTy::ReferenceType (node.get_hirid (), - TyTy::TyVar (node.get_hirid ()), - (is_mut) ? Mutability::Mut - : Mutability::Imm)); - } - else - { - translated = declare_variable (node); - } - - if (init.has_value ()) - { - push_assignment (translated, init.value ()); - } - } - - 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 (), - pattern.is_mut ()); - } - - void visit (HIR::ReferencePattern &pattern) override - { - SavedState saved (this); - - init = init.map ([&] (PlaceId id) { - return ctx.place_db.lookup_or_add_path (Place::DEREF, - lookup_type (pattern), id); - }); - - type_annotation = type_annotation.map ([&] (TyTy::BaseType *ty) { - return ty->as<TyTy::ReferenceType> ()->get_base (); - }); - - pattern.get_referenced_pattern ()->accept_vis (*this); - } - - void visit (HIR::SlicePattern &pattern) override - { - SavedState saved (this); - - // 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); - init = init.map ([&] (PlaceId id) { - return ctx.place_db.lookup_or_add_path (Place::INDEX, - lookup_type (pattern), id); - }); - - type_annotation = type_annotation.map ([&] (TyTy::BaseType *ty) { - return ty->as<TyTy::SliceType> ()->get_element_type (); - }); - - // Regions are unchnaged. - - 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); + location_t location, bool is_mut = false); - auto tyty = ctx.place_db[init.value ()].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); + void visit (HIR::IdentifierPattern &pattern) override; - 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 ()); + void visit (HIR::ReferencePattern &pattern) override; - init = init.map ([&] (PlaceId id) { - return ctx.place_db.lookup_or_add_path ( - Place::FIELD, lookup_type (*tuple->get_tuple_pattern ()), id, - tuple->get_index ()); - }); + void visit (HIR::SlicePattern &pattern) override; - type_annotation = type_annotation.map ([&] (TyTy::BaseType *ty) { - return ty->as<TyTy::ADTType> () - ->get_variants () - .at (0) - ->get_fields () - .at (tuple->get_index ()) - ->get_field_type (); - }); + void visit (HIR::AltPattern &pattern) override; - 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.value (), - 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.value (), - field_index); - visit_identifier (ident_field->get_mappings (), - ident_field->get_has_ref (), - ident_field->is_mut ()); - break; - } - } - } - } + void visit (HIR::StructPattern &pattern) override; void visit_tuple_fields (std::vector<std::unique_ptr<HIR::Pattern>> &fields, - SavedState &saved, size_t &index) - { - for (auto &item : fields) - { - auto type = lookup_type (*item); - - init = init.map ([&] (PlaceId id) { - return ctx.place_db.lookup_or_add_path (Place::FIELD, type, id, - index); - }); - - type_annotation = type_annotation.map ([&] (TyTy::BaseType *ty) { - return ty->as<TyTy::TupleType> () - ->get_fields () - .at (index) - .get_tyty (); - }); - - regions = regions.map ([&] (FreeRegions regs) { - return bind_regions (Resolver::TypeCheckContext::get () - ->get_variance_analysis_ctx () - .query_type_regions (type), - regs); - }); - - 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.value ()].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 (); + SavedState &saved, size_t &index); - 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::TuplePattern &pattern) override; - void visit (HIR::TupleStructPattern &pattern) override - { - SavedState saved (this); - - type_annotation = tl::nullopt; - - auto type = lookup_type (pattern); - - regions = regions.map ([&] (FreeRegions regs) { - return bind_regions (Resolver::TypeCheckContext::get () - ->get_variance_analysis_ctx () - .query_type_regions (type), - regs); - }); - - size_t index = 0; - switch (pattern.get_items ()->get_item_type ()) - { - case HIR::TupleStructItems::RANGED: { - auto &items - = static_cast<HIR::TupleStructItemsRange &> (*pattern.get_items ()); - - rust_assert (type->get_kind () == TyTy::ADT); - auto adt_ty = static_cast<TyTy::ADTType *> (type); - 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::MULTIPLE: { - auto &items = static_cast<HIR::TupleStructItemsNoRange &> ( - *pattern.get_items ()); - visit_tuple_fields (items.get_patterns (), saved, index); - break; - } - } - } + void visit (HIR::TupleStructPattern &pattern) override; void visit (HIR::WildcardPattern &pattern) override {} // Unused for binding. @@ -332,6 +91,7 @@ public: void visit (HIR::QualifiedPathInExpression &expression) override {} void visit (HIR::RangePattern &pattern) override {} }; + } // namespace BIR } // namespace Rust diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h b/gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h index 53346bf..84311cc 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h @@ -52,12 +52,12 @@ public: } void visit (HIR::StructExprFieldIdentifierValue &field) override { - auto value = ExprStmtBuilder (ctx).build (*field.get_value ()); + auto value = ExprStmtBuilder (ctx).build (field.get_value ()); handle_named_field (field, value); } void visit (HIR::StructExprFieldIndexValue &field) override { - auto value = ExprStmtBuilder (ctx).build (*field.get_value ()); + auto value = ExprStmtBuilder (ctx).build (field.get_value ()); coercion_site (value, struct_ty->get_field_at_index (field.get_tuple_index ()) ->get_field_type ()); @@ -149,12 +149,11 @@ protected: 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::InlineAsm &expr) override { rust_unreachable (); } + void visit (HIR::LlvmInlineAsm &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 @@ -252,10 +251,6 @@ protected: 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 (); } diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder.h b/gcc/rust/checks/errors/borrowck/rust-bir-builder.h index bafa22b4..e5bdb46 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-builder.h +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder.h @@ -49,7 +49,9 @@ public: for (auto ¶m : function.get_function_params ()) handle_param (param); - handle_body (*function.get_definition ()); + handle_body (function.get_definition ()); + auto region_hir_map + = map_region_to_hir (function.get_generic_params (), ctx.fn_free_regions); return Function{ std::move (ctx.place_db), @@ -57,6 +59,7 @@ public: std::move (ctx.basic_blocks), std::move (ctx.fn_free_regions), std::move (universal_region_bounds), + std::move (region_hir_map), function.get_locus (), }; } @@ -65,15 +68,15 @@ private: /** Instantiate `num_lifetime_params` free regions. */ void handle_lifetime_params (size_t num_lifetime_params) { - std::vector<FreeRegion> function_free_regions; + FreeRegions regions; for (size_t i = 0; i < num_lifetime_params; i++) { - function_free_regions.push_back (ctx.place_db.get_next_free_region ()); + regions.push_back (ctx.place_db.get_next_free_region ()); } rust_debug ("\tctx.fn_free_region={%s}", ctx.fn_free_regions.to_string ().c_str ()); - ctx.fn_free_regions.set_from (std::move (function_free_regions)); + ctx.fn_free_regions = regions; } void handle_lifetime_param_constraints ( @@ -91,8 +94,8 @@ private: ctx.fn_free_regions[bound.second.get_index ()]); auto last_bound = universal_region_bounds.back (); - rust_debug ("\t\t %lu: %lu", (unsigned long) last_bound.first, - (unsigned long) last_bound.second); + rust_debug ("\t\t %lu: %lu", (unsigned long) last_bound.first.value, + (unsigned long) last_bound.second.value); } // TODO: handle type_region constraints @@ -115,14 +118,14 @@ private: void handle_param (HIR::FunctionParam ¶m) { - auto param_type = lookup_type (*param.get_param_name ()); + auto param_type = lookup_type (param.get_param_name ()); auto &pattern = param.get_param_name (); - if (pattern->get_pattern_type () == HIR::Pattern::IDENTIFIER - && !static_cast<HIR::IdentifierPattern &> (*pattern).get_is_ref ()) + if (pattern.get_pattern_type () == HIR::Pattern::IDENTIFIER + && !static_cast<HIR::IdentifierPattern &> (pattern).get_is_ref ()) { // Avoid useless temporary variable for parameter to look like MIR. - translated = declare_variable (pattern->get_mappings ()); + translated = declare_variable (pattern.get_mappings ()); ctx.arguments.push_back (translated); } else @@ -130,11 +133,9 @@ private: translated = ctx.place_db.add_temporary (param_type); ctx.arguments.push_back (translated); PatternBindingBuilder (ctx, translated, tl::nullopt) - .go (*param.get_param_name ()); + .go (param.get_param_name ()); } - rust_assert (param.get_type () != nullptr); - // Set parameter place to use functions regions, not the fresh ones. ctx.place_db[translated].regions = bind_regions (Resolver::TypeCheckContext::get () @@ -152,10 +153,34 @@ private: { push_assignment (RETURN_VALUE_PLACE, ctx.place_db.get_constant ( - ctx.place_db[RETURN_VALUE_PLACE].tyty)); + ctx.place_db[RETURN_VALUE_PLACE].tyty), + body.get_end_locus ()); + } + auto return_location = body.has_expr () + ? body.get_final_expr ().get_locus () + : body.get_end_locus (); + push_return (return_location); + } + } + + // Maps named lifetime parameters to their respective HIR node + const std::unordered_map<Polonius::Origin, HIR::LifetimeParam *> + map_region_to_hir ( + const std::vector<std::unique_ptr<HIR::GenericParam>> &generic_params, + const FreeRegions ®ions) + { + std::unordered_map<Polonius::Origin, HIR::LifetimeParam *> result; + size_t region_index = 0; + for (auto &generic_param : generic_params) + { + if (generic_param->get_kind () + == HIR::GenericParam::GenericKind::LIFETIME) + { + result[regions[region_index++].value] + = static_cast<HIR::LifetimeParam *> (generic_param.get ()); } - ctx.get_current_bb ().statements.emplace_back (Statement::Kind::RETURN); } + return result; } }; diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-dump.cc b/gcc/rust/checks/errors/borrowck/rust-bir-dump.cc index a35f47b..3864b81 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-dump.cc +++ b/gcc/rust/checks/errors/borrowck/rust-bir-dump.cc @@ -53,21 +53,25 @@ renumber_places (const Function &func, std::vector<PlaceId> &place_map) { // Renumbering places to avoid gaps in the place id space. // This is needed to match MIR's shape. - size_t next_out_id = 0; + PlaceId next_out_id = INVALID_PLACE; - for (size_t in_id = FIRST_VARIABLE_PLACE; in_id < func.place_db.size (); - ++in_id) + for (PlaceId in_id = FIRST_VARIABLE_PLACE; + in_id.value < func.place_db.size (); ++in_id.value) { const Place &place = func.place_db[in_id]; if (place.kind == Place::VARIABLE || place.kind == Place::TEMPORARY) - place_map[in_id] = next_out_id++; + { + place_map[in_id.value] = next_out_id; + ++next_out_id.value; + } + else - place_map[in_id] = INVALID_PLACE; + place_map[in_id.value] = INVALID_PLACE; } } void -simplify_cfg (Function &func, std::vector<BasicBlockId> &bb_fold_map) +simplify_cfg (Function &func, IndexVec<BasicBlockId, BasicBlockId> &bb_fold_map) { // The BIR builder can generate many useless basic blocks, which contain only // a goto. @@ -78,7 +82,7 @@ simplify_cfg (Function &func, std::vector<BasicBlockId> &bb_fold_map) { stabilized = true; // BB0 cannot be folded as it is an entry block. - for (size_t i = 1; i < func.basic_blocks.size (); ++i) + for (BasicBlockId i = {1}; i.value < func.basic_blocks.size (); ++i.value) { const BasicBlock &bb = func.basic_blocks[bb_fold_map[i]]; if (bb.statements.empty () && bb.is_goto_terminated ()) @@ -93,7 +97,11 @@ simplify_cfg (Function &func, std::vector<BasicBlockId> &bb_fold_map) rust_inform (UNKNOWN_LOCATION, "Continuing with an unfolded CFG."); // Reverting the fold map to the original state. - std::iota (bb_fold_map.begin (), bb_fold_map.end (), 0); + for (BasicBlockId i = ENTRY_BASIC_BLOCK; + i.value < bb_fold_map.size (); ++i.value) + { + bb_fold_map[i] = i; + } stabilized = true; break; } @@ -108,9 +116,15 @@ void Dump::go (bool enable_simplify_cfg) { // To avoid mutation of the BIR, we use indirection through bb_fold_map. - std::iota (bb_fold_map.begin (), bb_fold_map.end (), 0); - - std::iota (place_map.begin (), place_map.end (), 0); + for (BasicBlockId i = ENTRY_BASIC_BLOCK; i.value < bb_fold_map.size (); + ++i.value) + { + bb_fold_map[i] = i; + } + for (PlaceId i = INVALID_PLACE; i.value < place_map.size (); ++i.value) + { + place_map[i] = i; + } if (enable_simplify_cfg) simplify_cfg (func, bb_fold_map); @@ -119,18 +133,18 @@ Dump::go (bool enable_simplify_cfg) stream << "fn " << name << "("; print_comma_separated (stream, func.arguments, [this] (PlaceId place_id) { - stream << "_" << place_map[place_id] << ": " + stream << "_" << place_map[place_id].value << ": " << get_tyty_name (func.place_db[place_id].tyty); }); stream << ") -> " << get_tyty_name (func.place_db[RETURN_VALUE_PLACE].tyty); stream << " {\n"; // Print locals declaration. - visit_scope (0); + visit_scope (ROOT_SCOPE); // Print BBs. - for (statement_bb = 0; statement_bb < func.basic_blocks.size (); - ++statement_bb) + for (statement_bb = ENTRY_BASIC_BLOCK; + statement_bb.value < func.basic_blocks.size (); ++statement_bb.value) { if (bb_fold_map[statement_bb] != statement_bb) continue; // This BB was folded. @@ -143,7 +157,8 @@ Dump::go (bool enable_simplify_cfg) BasicBlock &bb = func.basic_blocks[statement_bb]; stream << "\n"; - stream << indentation << "bb" << bb_fold_map[statement_bb] << ": {\n"; + stream << indentation << "bb" << bb_fold_map[statement_bb].value + << ": {\n"; size_t i = 0; for (auto &stmt : bb.statements) { @@ -153,7 +168,8 @@ Dump::go (bool enable_simplify_cfg) } if (!bb_terminated) stream << indentation << indentation << "goto -> bb" - << bb_fold_map[bb.successors.at (0)] << ";\t\t" << i++ << "\n"; + << bb_fold_map[bb.successors.at (0)].value << ";\t\t" << i++ + << "\n"; stream << indentation << "}\n"; } @@ -178,7 +194,7 @@ Dump::visit (const Statement &stmt) stream << ") -> ["; print_comma_separated (stream, func.basic_blocks[statement_bb].successors, [this] (BasicBlockId succ) { - stream << "bb" << bb_fold_map[succ]; + stream << "bb" << bb_fold_map[succ].value; }); stream << "]"; bb_terminated = true; @@ -188,8 +204,9 @@ Dump::visit (const Statement &stmt) bb_terminated = true; break; case Statement::Kind::GOTO: - stream << "goto -> bb" - << bb_fold_map[func.basic_blocks[statement_bb].successors.at (0)]; + stream + << "goto -> bb" + << bb_fold_map[func.basic_blocks[statement_bb].successors.at (0)].value; bb_terminated = true; break; case Statement::Kind::STORAGE_DEAD: @@ -228,7 +245,7 @@ Dump::visit_place (PlaceId place_id) { case Place::TEMPORARY: case Place::VARIABLE: - stream << "_" << place_map[place_id]; + stream << "_" << place_map[place_id].value; break; case Place::DEREF: stream << "("; @@ -272,7 +289,7 @@ Dump::visit (const BorrowExpr &expr) { stream << "&" << "'?" << expr.get_origin () << " "; - if (func.place_db.get_loans ()[expr.get_loan ()].mutability + if (func.place_db.get_loan (expr.get_loan_id ()).mutability == Mutability::Mut) stream << "mut "; visit_place (expr.get_place ()); @@ -311,7 +328,7 @@ Dump::visit (const CallExpr &expr) stream << ") -> ["; print_comma_separated (stream, func.basic_blocks[statement_bb].successors, [this] (BasicBlockId succ) { - stream << "bb" << bb_fold_map[succ]; + stream << "bb" << bb_fold_map[succ].value; }); stream << "]"; bb_terminated = true; @@ -359,13 +376,13 @@ Dump::visit_scope (ScopeId id, size_t depth) if (scope.locals.empty () && scope.children.empty ()) return; - if (id > 1) - indent (depth) << "scope " << id - 1 << " {\n"; + if (id.value > 1) + indent (depth) << "scope " << id.value - 1 << " {\n"; for (auto &local : scope.locals) { indent (depth + 1) << "let _"; - stream << place_map[local] << ": " + stream << place_map[local].value << ": " << get_tyty_name (func.place_db[local].tyty); stream << ";\t"; @@ -373,14 +390,14 @@ Dump::visit_scope (ScopeId id, size_t depth) print_comma_separated (stream, func.place_db[local].regions.get_regions (), [this] (FreeRegion region_id) { - stream << "'?" << region_id; + stream << "'?" << region_id.value; }); stream << "]\n"; } for (auto &child : scope.children) - visit_scope (child, (id >= 1) ? depth + 1 : depth); + visit_scope (child, (id.value >= 1) ? depth + 1 : depth); - if (id > 1) + if (id.value > 1) indent (depth) << "}\n"; } diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-dump.h b/gcc/rust/checks/errors/borrowck/rust-bir-dump.h index e88681f..1bf3f2d 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-dump.h +++ b/gcc/rust/checks/errors/borrowck/rust-bir-dump.h @@ -34,8 +34,8 @@ class Dump : public Visitor Function &func; const std::string &name; - std::vector<BasicBlockId> bb_fold_map; - std::vector<PlaceId> place_map; + IndexVec<BasicBlockId, BasicBlockId> bb_fold_map; + IndexVec<PlaceId, PlaceId> place_map; PlaceId statement_place = INVALID_PLACE; BasicBlockId statement_bb = INVALID_BB; diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-fact-collector.h b/gcc/rust/checks/errors/borrowck/rust-bir-fact-collector.h index 9999bdd..32a4cd7 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-fact-collector.h +++ b/gcc/rust/checks/errors/borrowck/rust-bir-fact-collector.h @@ -40,14 +40,14 @@ class FactCollector : public Visitor // Read-only context. const PlaceDB &place_db; - const std::vector<BasicBlock> &basic_blocks; + const BasicBlocks &basic_blocks; const PlaceId first_local; const location_t location; Resolver::TypeCheckContext &tyctx; // Collector state. - BasicBlockId current_bb = 0; + BasicBlockId current_bb = ENTRY_BASIC_BLOCK; uint32_t current_stmt = 0; PlaceId lhs = INVALID_PLACE; @@ -65,11 +65,11 @@ class FactCollector : public Visitor FreeRegions make_fresh_regions (size_t size) { - std::vector<FreeRegion> free_regions; + FreeRegions free_regions; for (size_t i = 0; i < size; i++) free_regions.push_back (region_binder.get_next_free_region ()); - return FreeRegions (std::move (free_regions)); + return free_regions; } public: @@ -88,8 +88,9 @@ public: protected: // Constructor and destructor. explicit FactCollector (Function &func) : place_db (func.place_db), basic_blocks (func.basic_blocks), - first_local (func.arguments.empty () ? FIRST_VARIABLE_PLACE - : *func.arguments.rbegin () + 1), + first_local (func.arguments.empty () + ? FIRST_VARIABLE_PLACE + : PlaceId{func.arguments.rbegin ()->value + 1}), location (func.location), tyctx (*Resolver::TypeCheckContext::get ()), next_fresh_region (place_db.peek_next_free_region ()) {} @@ -106,19 +107,21 @@ protected: // Main collection entry points (for different categories). for (auto ®ion : universal_regions) { - facts.universal_region.emplace_back (region); - facts.placeholder.emplace_back (region, next_loan++); - facts.known_placeholder_subset.emplace_back (0, region); + facts.universal_region.emplace_back (region.value); + facts.placeholder.emplace_back (region.value, next_loan++); + facts.known_placeholder_subset.emplace_back (0, region.value); } // Copy already collected subset facts, that are universally valid. for (auto &bound : universal_region_bounds) - facts.known_placeholder_subset.emplace_back (bound.first, bound.second); + facts.known_placeholder_subset.emplace_back (bound.first.value, + bound.second.value); } void visit_places (const std::vector<PlaceId> &args) { - for (PlaceId place_id = 0; place_id < place_db.size (); ++place_id) + for (PlaceId place_id = INVALID_PLACE; place_id.value < place_db.size (); + ++place_id.value) { auto &place = place_db[place_id]; @@ -126,24 +129,28 @@ protected: // Main collection entry points (for different categories). { case Place::VARIABLE: case Place::TEMPORARY: - facts.path_is_var.emplace_back (place_id, place_id); + facts.path_is_var.emplace_back (place_id.value, place_id.value); for (auto ®ion : place.regions) - facts.use_of_var_derefs_origin.emplace_back (place_id, region); + facts.use_of_var_derefs_origin.emplace_back (place_id.value, + region.value); // TODO: drop_of_var_derefs_origin break; case Place::FIELD: sanizite_field (place_id); - facts.child_path.emplace_back (place_id, place.path.parent); + facts.child_path.emplace_back (place_id.value, + place.path.parent.value); break; case Place::INDEX: push_subset_all (place.tyty, place.regions, place_db[place.path.parent].regions); - facts.child_path.emplace_back (place_id, place.path.parent); + facts.child_path.emplace_back (place_id.value, + place.path.parent.value); break; case Place::DEREF: sanitize_deref (place_id); - facts.child_path.emplace_back (place_id, place.path.parent); + facts.child_path.emplace_back (place_id.value, + place.path.parent.value); break; case Place::CONSTANT: case Place::INVALID: @@ -151,15 +158,18 @@ protected: // Main collection entry points (for different categories). } } - for (PlaceId arg = FIRST_VARIABLE_PLACE + 1; arg < first_local; ++arg) + for (PlaceId arg = PlaceId{FIRST_VARIABLE_PLACE.value + 1}; + arg < first_local; ++arg.value) facts.path_assigned_at_base.emplace_back ( - arg, get_point (0, 0, PointPosition::START)); + arg.value, get_point (ENTRY_BASIC_BLOCK, 0, PointPosition::START)); - for (PlaceId place = first_local; place < place_db.size (); ++place) + for (PlaceId place = first_local; place.value < place_db.size (); + ++place.value) { if (place_db[place].is_var ()) facts.path_moved_at_base.emplace_back ( - place, get_point (0, 0, PointPosition::START)); + place.value, + get_point (ENTRY_BASIC_BLOCK, 0, PointPosition::START)); } } @@ -170,11 +180,12 @@ protected: // Main collection entry points (for different categories). rust_debug ("\tSanitize deref of %s", base.tyty->as_string ().c_str ()); - std::vector<Polonius::Origin> regions; - regions.insert (regions.end (), base.regions.begin () + 1, - base.regions.end ()); - FreeRegions r (std::move (regions)); - push_subset_all (place.tyty, r, place.regions); + FreeRegions regions; + for (auto it = base.regions.begin () + 1; it != base.regions.end (); ++it) + { + regions.push_back (*it); + } + push_subset_all (place.tyty, regions, place.regions); } void sanizite_field (PlaceId place_id) { @@ -191,15 +202,15 @@ protected: // Main collection entry points (for different categories). .query_field_regions (base.tyty->as<TyTy::ADTType> (), 0, place.variable_or_field_index, base.regions); // FIXME - FreeRegions f (std::move (r)); - push_subset_all (place.tyty, f, place.regions); + push_subset_all (place.tyty, r, place.regions); } void visit_statemensts () { rust_debug ("visit_statemensts"); - for (current_bb = 0; current_bb < basic_blocks.size (); ++current_bb) + for (current_bb = ENTRY_BASIC_BLOCK; + current_bb.value < basic_blocks.size (); ++current_bb.value) { auto &bb = basic_blocks[current_bb]; for (current_stmt = 0; current_stmt < bb.statements.size (); @@ -213,7 +224,7 @@ protected: // Main collection entry points (for different categories). visit (bb.statements[current_stmt]); } } - current_bb = 0; + current_bb = ENTRY_BASIC_BLOCK; current_stmt = 0; } @@ -242,9 +253,9 @@ protected: // Main collection entry points (for different categories). break; } case Statement::Kind::STORAGE_DEAD: { - facts.path_moved_at_base.emplace_back (stmt.get_place (), + facts.path_moved_at_base.emplace_back (stmt.get_place ().value, get_current_point_mid ()); - facts.var_defined_at.emplace_back (stmt.get_place (), + facts.var_defined_at.emplace_back (stmt.get_place ().value, get_current_point_mid ()); break; } @@ -293,9 +304,10 @@ protected: // Main collection entry points (for different categories). void visit (const BorrowExpr &expr) override { - rust_debug ("\t_%u = BorrowExpr(_%u)", lhs - 1, expr.get_place () - 1); + rust_debug ("\t_%u = BorrowExpr(_%u)", lhs.value - 1, + expr.get_place ().value - 1); - auto loan = place_db.get_loans ()[expr.get_loan ()]; + auto loan = place_db.get_loan (expr.get_loan_id ()); auto &base_place = place_db[expr.get_place ()]; auto &ref_place = place_db[lhs]; @@ -314,24 +326,24 @@ protected: // Main collection entry points (for different categories). ->is_mutable ()) rust_error_at (location, "Cannot reborrow immutable borrow as mutable"); - issue_loan (expr.get_origin (), expr.get_loan ()); + issue_loan (expr.get_origin (), expr.get_loan_id ()); } - push_subset (main_loan_place.regions[0], expr.get_origin ()); + push_subset (main_loan_place.regions[0], {expr.get_origin ()}); } else { - issue_loan (expr.get_origin (), expr.get_loan ()); + issue_loan (expr.get_origin (), expr.get_loan_id ()); } - auto loan_regions = base_place.regions.prepend (expr.get_origin ()); + auto loan_regions = base_place.regions.prepend ({expr.get_origin ()}); push_subset (ref_place.tyty, loan_regions, ref_place.regions); } void visit (const Assignment &expr) override { - rust_debug ("\t_%u = Assignment(_%u) at %u:%u", lhs - 1, - expr.get_rhs () - 1, current_bb, current_stmt); + rust_debug ("\t_%u = Assignment(_%u) at %u:%u", lhs.value - 1, + expr.get_rhs ().value - 1, current_bb.value, current_stmt); issue_read_move (expr.get_rhs ()); push_place_subset (lhs, expr.get_rhs ()); @@ -339,7 +351,8 @@ protected: // Main collection entry points (for different categories). void visit (const CallExpr &expr) override { - rust_debug ("\t_%u = CallExpr(_%u)", lhs - 1, expr.get_callable () - 1); + rust_debug ("\t_%u = CallExpr(_%u)", lhs.value - 1, + expr.get_callable ().value - 1); auto &return_place = place_db[lhs]; auto &callable_place = place_db[expr.get_callable ()]; @@ -387,7 +400,7 @@ protected: // Statement visitor helpers get_point (BasicBlockId bb, uint32_t stmt, PointPosition pos) { Polonius::Point point = 0; - point |= (bb << 16); + point |= (bb.value << 16); point |= (stmt << 1); point |= (static_cast<uint8_t> (pos) & 1); return point; @@ -434,14 +447,14 @@ protected: // Generic BIR operations. return; if (place_id != RETURN_VALUE_PLACE) - facts.path_accessed_at_base.emplace_back (place_id, + facts.path_accessed_at_base.emplace_back (place_id.value, get_current_point_mid ()); if (place.is_var ()) - facts.var_used_at.emplace_back (place_id, get_current_point_mid ()); + facts.var_used_at.emplace_back (place_id.value, get_current_point_mid ()); else if (place.is_path ()) { - facts.var_used_at.emplace_back (place_db.get_var (place_id), + facts.var_used_at.emplace_back (place_db.get_var (place_id).value, get_current_point_mid ()); } } @@ -468,11 +481,12 @@ protected: // Generic BIR operations. rust_assert (place.is_lvalue () || place.is_rvalue ()); if (place.is_var ()) - facts.var_defined_at.emplace_back (place_id, get_current_point_mid ()); + facts.var_defined_at.emplace_back (place_id.value, + get_current_point_mid ()); if (!is_init) { - facts.path_assigned_at_base.emplace_back (place_id, + facts.path_assigned_at_base.emplace_back (place_id.value, get_current_point_mid ()); check_write_for_conflict (place_id); kill_borrows_for_place (place_id); @@ -484,9 +498,11 @@ protected: // Generic BIR operations. if (!place_db[place_id].should_be_moved ()) return; - facts.path_moved_at_base.emplace_back ( - place_id, initial ? get_point (0, 0, PointPosition::START) - : get_current_point_mid ()); + facts.path_moved_at_base.emplace_back (place_id.value, + initial + ? get_point (ENTRY_BASIC_BLOCK, 0, + PointPosition::START) + : get_current_point_mid ()); check_move_behind_reference (place_id); @@ -499,24 +515,25 @@ protected: // Generic BIR operations. void issue_loan (Polonius::Origin origin, LoanId loan_id) { - facts.loan_issued_at.emplace_back (origin, loan_id, + facts.loan_issued_at.emplace_back (origin, loan_id.value, get_current_point_mid ()); - check_for_borrow_conficts (place_db.get_loans ()[loan_id].place, loan_id, - place_db.get_loans ()[loan_id].mutability); + check_for_borrow_conficts (place_db.get_loan (loan_id).place, loan_id, + place_db.get_loan (loan_id).mutability); } void issue_locals_dealloc () { - for (LoanId loan_id = 0; loan_id < place_db.get_loans ().size (); ++loan_id) + for (LoanId loan_id = {0}; loan_id.value < place_db.get_loans ().size (); + ++loan_id.value) { - auto &loan = place_db.get_loans ()[loan_id]; + auto &loan = place_db.get_loan (loan_id); auto loaned_var_id = place_db.get_var (loan.place); if (place_db[loaned_var_id].tyty->is<TyTy::ReferenceType> ()) continue; if (loaned_var_id >= first_local) facts.loan_invalidated_at.emplace_back (get_current_point_start (), - loan_id); + loan_id.value); } } @@ -534,20 +551,20 @@ protected: // Generic BIR operations. place_db.for_each_path_segment (place_id, [&] (PlaceId id) { for (auto loan : place_db[id].borrowed_by) { - if (place_db.get_loans ()[loan].mutability == Mutability::Mut) + if (place_db.get_loan (loan).mutability == Mutability::Mut) { facts.loan_invalidated_at.emplace_back ( - get_current_point_start (), loan); + get_current_point_start (), loan.value); } } }); place_db.for_each_path_from_root (place_id, [&] (PlaceId id) { for (auto loan : place_db[id].borrowed_by) { - if (place_db.get_loans ()[loan].mutability == Mutability::Mut) + if (place_db.get_loan (loan).mutability == Mutability::Mut) { facts.loan_invalidated_at.emplace_back ( - get_current_point_start (), loan); + get_current_point_start (), loan.value); } } }); @@ -558,12 +575,12 @@ protected: // Generic BIR operations. place_db.for_each_path_segment (place_id, [&] (PlaceId id) { for (auto loan : place_db[id].borrowed_by) facts.loan_invalidated_at.emplace_back (get_current_point_start (), - loan); + loan.value); }); place_db.for_each_path_from_root (place_id, [&] (PlaceId id) { for (auto loan : place_db[id].borrowed_by) facts.loan_invalidated_at.emplace_back (get_current_point_start (), - loan); + loan.value); }); } @@ -574,12 +591,11 @@ protected: // Generic BIR operations. for (auto other_loan : place_db[id].borrowed_by) { if (mutability == Mutability::Imm - && place_db.get_loans ()[other_loan].mutability - == Mutability::Imm) + && place_db.get_loan (other_loan).mutability == Mutability::Imm) continue; else facts.loan_invalidated_at.emplace_back (get_current_point_start (), - other_loan); + other_loan.value); } }); @@ -587,12 +603,11 @@ protected: // Generic BIR operations. for (auto other_loan : place_db[id].borrowed_by) { if (mutability == Mutability::Imm - && place_db.get_loans ()[other_loan].mutability - == Mutability::Imm) + && place_db.get_loan (other_loan).mutability == Mutability::Imm) continue; else facts.loan_invalidated_at.emplace_back (get_current_point_start (), - other_loan); + other_loan.value); } }); } @@ -614,26 +629,28 @@ protected: // Generic BIR operations. { // TODO: this is more complicated, see // compiler/rustc_borrowck/src/constraint_generation.rs:176 - facts.loan_killed_at.emplace_back (loan, get_current_point_mid ()); + facts.loan_killed_at.emplace_back (loan.value, + get_current_point_mid ()); } } protected: // Subset helpers. void push_subset (FreeRegion lhs, FreeRegion rhs) { - rust_debug ("\t\tpush_subset: '?%lu: '?%lu", (unsigned long) lhs, - (unsigned long) rhs); + rust_debug ("\t\tpush_subset: '?%lu: '?%lu", (unsigned long) lhs.value, + (unsigned long) rhs.value); - facts.subset_base.emplace_back (lhs, rhs, get_current_point_mid ()); + facts.subset_base.emplace_back (lhs.value, rhs.value, + get_current_point_mid ()); } void push_subset_all (FreeRegion lhs, FreeRegion rhs) { - rust_debug ("\t\tpush_subset_all: '?%lu: '?%lu", (unsigned long) lhs, - (unsigned long) rhs); + rust_debug ("\t\tpush_subset_all: '?%lu: '?%lu", (unsigned long) lhs.value, + (unsigned long) rhs.value); for (auto point : cfg_points_all) - facts.subset_base.emplace_back (lhs, rhs, point); + facts.subset_base.emplace_back (lhs.value, rhs.value, point); } void push_subset (Variance variance, FreeRegion lhs, FreeRegion rhs) @@ -798,6 +815,7 @@ protected: // Subset helpers. case TyTy::PLACEHOLDER: case TyTy::INFER: case TyTy::PARAM: + case TyTy::OPAQUE: rust_unreachable (); } rust_unreachable (); diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-free-region.h b/gcc/rust/checks/errors/borrowck/rust-bir-free-region.h index c09e888..cb459f8 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-free-region.h +++ b/gcc/rust/checks/errors/borrowck/rust-bir-free-region.h @@ -24,7 +24,19 @@ namespace Rust { -using FreeRegion = size_t; +struct FreeRegion +{ + size_t value; + // some overloads for comparision + bool operator== (const FreeRegion &rhs) const { return value == rhs.value; } + bool operator!= (const FreeRegion &rhs) const { return !(operator== (rhs)); } + bool operator< (const FreeRegion &rhs) const { return value < rhs.value; } + bool operator> (const FreeRegion &rhs) const { return value > rhs.value; } + bool operator<= (const FreeRegion &rhs) const { return !(operator> (rhs)); } + bool operator>= (const FreeRegion &rhs) const { return !(operator< (rhs)); } +}; + +static constexpr FreeRegion STATIC_FREE_REGION = {0}; class FreeRegions { @@ -38,14 +50,6 @@ public: FreeRegion &operator[] (size_t i) { return regions.at (i); } const FreeRegion &operator[] (size_t i) const { return regions.at (i); } const std::vector<FreeRegion> &get_regions () const { return regions; } - void set_from (std::vector<Rust::Polonius::Origin> &®ions) - { - this->regions.clear (); - for (auto ®ion : regions) - { - this->regions.push_back ({region}); - } - } WARN_UNUSED_RESULT FreeRegions prepend (FreeRegion region) const { @@ -54,6 +58,9 @@ public: return FreeRegions (std::move (new_regions)); } + void push_back (FreeRegion region) { regions.push_back (region); } + + FreeRegions () {} FreeRegions (std::vector<FreeRegion> &®ions) : regions (regions) {} WARN_UNUSED_RESULT std::string to_string () const @@ -61,7 +68,7 @@ public: std::stringstream result; for (auto ®ion : regions) { - result << region; + result << region.value; result << ", "; } // Remove the last ", " from the string. @@ -83,19 +90,20 @@ public: WARN_UNUSED_RESULT FreeRegion get_next_free_region () const { - return next_free_region++; + ++next_free_region.value; + return {next_free_region.value - 1}; } FreeRegions bind_regions (std::vector<TyTy::Region> regions, FreeRegions parent_free_regions) { - std::vector<FreeRegion> free_regions; + FreeRegions free_regions; for (auto ®ion : regions) { if (region.is_early_bound ()) free_regions.push_back (parent_free_regions[region.get_index ()]); else if (region.is_static ()) - free_regions.push_back (0); + free_regions.push_back (STATIC_FREE_REGION); else if (region.is_anonymous ()) free_regions.push_back (get_next_free_region ()); else if (region.is_named ()) @@ -106,9 +114,7 @@ public: rust_unreachable (); } } - // This is necesarry because of clash of current gcc and gcc4.8. - FreeRegions free_regions_final{std::move (free_regions)}; - return free_regions_final; + return free_regions; } }; diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-place.h b/gcc/rust/checks/errors/borrowck/rust-bir-place.h index 8c38e8e..dd9e672 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-place.h +++ b/gcc/rust/checks/errors/borrowck/rust-bir-place.h @@ -32,14 +32,36 @@ namespace Rust { namespace BIR { /** A unique identifier for a place in the BIR. */ -using PlaceId = uint32_t; +struct PlaceId +{ + uint32_t value; + // some overloads for comparision + bool operator== (const PlaceId &rhs) const { return value == rhs.value; } + bool operator!= (const PlaceId &rhs) const { return !(operator== (rhs)); } + bool operator< (const PlaceId &rhs) const { return value < rhs.value; } + bool operator> (const PlaceId &rhs) const { return value > rhs.value; } + bool operator<= (const PlaceId &rhs) const { return !(operator> (rhs)); } + bool operator>= (const PlaceId &rhs) const { return !(operator< (rhs)); } +}; -static constexpr PlaceId INVALID_PLACE = 0; -static constexpr PlaceId RETURN_VALUE_PLACE = 1; +static constexpr PlaceId INVALID_PLACE = {0}; +static constexpr PlaceId RETURN_VALUE_PLACE = {1}; static constexpr PlaceId FIRST_VARIABLE_PLACE = RETURN_VALUE_PLACE; using Variance = TyTy::VarianceAnalysis::Variance; -using LoanId = uint32_t; + +/** A unique identifier for a loan in the BIR. */ +struct LoanId +{ + uint32_t value; + // some overloads for comparision + bool operator== (const LoanId &rhs) const { return value == rhs.value; } + bool operator!= (const LoanId &rhs) const { return !(operator== (rhs)); } + bool operator< (const LoanId &rhs) const { return value < rhs.value; } + bool operator> (const LoanId &rhs) const { return value > rhs.value; } + bool operator<= (const LoanId &rhs) const { return !(operator> (rhs)); } + bool operator>= (const LoanId &rhs) const { return !(operator< (rhs)); } +}; /** * Representation of lvalues and constants in BIR. @@ -143,13 +165,25 @@ public: } }; -using ScopeId = uint32_t; +struct ScopeId +{ + uint32_t value; + ScopeId next_scope_id () const { return {value + 1}; } + // some overloads for comparision + bool operator== (const ScopeId &rhs) const { return value == rhs.value; } + bool operator!= (const ScopeId &rhs) const { return !(operator== (rhs)); } + bool operator< (const ScopeId &rhs) const { return value < rhs.value; } + bool operator> (const ScopeId &rhs) const { return value > rhs.value; } + bool operator<= (const ScopeId &rhs) const { return !(operator> (rhs)); } + bool operator>= (const ScopeId &rhs) const { return !(operator< (rhs)); } +}; -static constexpr ScopeId INVALID_SCOPE = std::numeric_limits<ScopeId>::max (); +static constexpr ScopeId INVALID_SCOPE + = {std::numeric_limits<uint32_t>::max ()}; /** Arguments and return value are in the root scope. */ -static constexpr ScopeId ROOT_SCOPE = 0; +static constexpr ScopeId ROOT_SCOPE = {0}; /** Top-level local variables are in the top-level scope. */ -static constexpr ScopeId TOP_LEVEL_SCOPE = 1; +static constexpr ScopeId TOP_LEVEL_SCOPE = {1}; struct Scope { @@ -162,21 +196,58 @@ struct Loan { Mutability mutability; PlaceId place; + location_t location; }; +// I is the index type, T is the contained type +template <typename I, typename T> class IndexVec +{ + std::vector<T> internal_vector; + + typedef decltype (std::declval<I> ().value) size_type; + static constexpr auto MAX_INDEX = std::numeric_limits<size_type>::max (); + +public: + IndexVec () = default; + IndexVec (size_t size) { internal_vector.reserve (size); } + + T &at (I pid) { return internal_vector[pid.value]; } + const T &at (I pid) const { return internal_vector[pid.value]; } + T &operator[] (I pid) { return internal_vector[pid.value]; } + const T &operator[] (I pid) const { return internal_vector[pid.value]; } + + void push_back (T &¶m) { internal_vector.push_back (std::move (param)); } + template <typename... Args> void emplace_back (Args &&... args) + { + internal_vector.emplace_back (std::forward<Args> (args)...); + } + + size_type size () const + { + rust_assert (internal_vector.size () < MAX_INDEX); + return static_cast<size_type> (internal_vector.size ()); + } + + std::vector<T> &get_vector () { return internal_vector; } +}; + +using Scopes = IndexVec<ScopeId, Scope>; +using Loans = IndexVec<LoanId, Loan>; +using Places = IndexVec<PlaceId, Place>; + /** Allocated places and keeps track of paths. */ class PlaceDB { private: // Possible optimizations: separate variables to speedup lookup. - std::vector<Place> places; + Places places; std::unordered_map<TyTy::BaseType *, PlaceId> constants_lookup; - std::vector<Scope> scopes; - ScopeId current_scope = 0; + Scopes scopes; + ScopeId current_scope = ROOT_SCOPE; - std::vector<Loan> loans; + Loans loans; - Polonius::Origin next_free_region = 1; + FreeRegion next_free_region = {1}; public: PlaceDB () @@ -190,22 +261,24 @@ public: Place &operator[] (PlaceId id) { return places.at (id); } const Place &operator[] (PlaceId id) const { return places.at (id); } - decltype (places)::const_iterator begin () const { return places.begin (); } - decltype (places)::const_iterator end () const { return places.end (); } - size_t size () const { return places.size (); } - const std::vector<Loan> &get_loans () const { return loans; } + const Loans &get_loans () const { return loans; } + const Loan &get_loan (LoanId loan_id) const { return loans.at (loan_id); } ScopeId get_current_scope_id () const { return current_scope; } - const std::vector<Scope> &get_scopes () const { return scopes; } + const Scopes &get_scopes () const { return scopes; } const Scope &get_current_scope () const { return scopes[current_scope]; } const Scope &get_scope (ScopeId id) const { return scopes[id]; } - FreeRegion get_next_free_region () { return next_free_region++; } + FreeRegion get_next_free_region () + { + ++next_free_region.value; + return {next_free_region.value - 1}; + } FreeRegion peek_next_free_region () const { return next_free_region; } @@ -213,7 +286,7 @@ public: ScopeId push_new_scope () { - ScopeId new_scope = scopes.size (); + ScopeId new_scope = {scopes.size ()}; scopes.emplace_back (); scopes[new_scope].parent = current_scope; scopes[current_scope].children.push_back (new_scope); @@ -227,12 +300,12 @@ public: return current_scope; } - PlaceId add_place (Place &&place, PlaceId last_sibling = 0) + PlaceId add_place (Place &&place, PlaceId last_sibling = INVALID_PLACE) { places.emplace_back (std::forward<Place &&> (place)); - PlaceId new_place = places.size () - 1; + PlaceId new_place = {places.size () - 1}; Place &new_place_ref = places[new_place]; // Intentional shadowing. - if (last_sibling == 0) + if (last_sibling == INVALID_PLACE) places[new_place_ref.path.parent].path.first_child = new_place; else places[last_sibling].path.next_sibling = new_place; @@ -244,29 +317,33 @@ public: auto variances = Resolver::TypeCheckContext::get () ->get_variance_analysis_ctx () .query_type_variances (new_place_ref.tyty); - std::vector<Polonius::Origin> regions; - for (size_t i = 0; i < variances.size (); i++) - regions.push_back (next_free_region++); + FreeRegions regions; + for (size_t i = 0; i < variances.size (); ++i) + { + regions.push_back (next_free_region); + ++next_free_region.value; + } - new_place_ref.regions.set_from (std::move (regions)); + new_place_ref.regions = regions; return new_place; } PlaceId add_variable (NodeId id, TyTy::BaseType *tyty) { - return add_place ({Place::VARIABLE, id, {}, is_type_copy (tyty), tyty}, 0); + return add_place ({Place::VARIABLE, id, {}, is_type_copy (tyty), tyty}, + INVALID_PLACE); } WARN_UNUSED_RESULT PlaceId lookup_or_add_path (Place::Kind kind, TyTy::BaseType *tyty, PlaceId parent, size_t id = 0) { - PlaceId current = 0; - if (parent < places.size ()) + PlaceId current = INVALID_PLACE; + if (parent.value < places.size ()) { current = places[parent].path.first_child; - while (current != 0) + while (current != INVALID_PLACE) { if (places[current].kind == kind && places[current].variable_or_field_index == id) @@ -277,14 +354,16 @@ public: current = places[current].path.next_sibling; } } - return add_place ({kind, (uint32_t) id, Place::Path{parent, 0, 0}, + return add_place ({kind, (uint32_t) id, + Place::Path{parent, INVALID_PLACE, INVALID_PLACE}, is_type_copy (tyty), tyty}, current); } PlaceId add_temporary (TyTy::BaseType *tyty) { - return add_place ({Place::TEMPORARY, 0, {}, is_type_copy (tyty), tyty}, 0); + return add_place ({Place::TEMPORARY, 0, {}, is_type_copy (tyty), tyty}, + INVALID_PLACE); } PlaceId get_constant (TyTy::BaseType *tyty) @@ -299,22 +378,22 @@ public: { PlaceId current = FIRST_VARIABLE_PLACE; - while (current != places.size ()) + while (current.value != places.size ()) { if (places[current].kind == Place::VARIABLE && places[current].variable_or_field_index == id) return current; - current++; + ++current.value; } return INVALID_PLACE; } LoanId add_loan (Loan &&loan) { - LoanId id = loans.size (); + LoanId id = {loans.size ()}; loans.push_back (std::forward<Loan &&> (loan)); - PlaceId borrowed_place = loans.rbegin ()->place; - places[loans.rbegin ()->place].borrowed_by.push_back (id); + PlaceId borrowed_place = loans.get_vector ().rbegin ()->place; + places[loans.get_vector ().rbegin ()->place].borrowed_by.push_back (id); if (places[borrowed_place].kind == Place::DEREF) { places[places[borrowed_place].path.parent].borrowed_by.push_back (id); @@ -337,7 +416,7 @@ public: void set_next_free_region (Polonius::Origin next_free_region) { - this->next_free_region = next_free_region; + this->next_free_region.value = next_free_region; } PlaceId lookup_or_add_variable (NodeId id, TyTy::BaseType *tyty) @@ -346,8 +425,7 @@ public: if (lookup != INVALID_PLACE) return lookup; - add_place ({Place::VARIABLE, id, {}, is_type_copy (tyty), tyty}); - return places.size () - 1; + return add_place ({Place::VARIABLE, id, {}, is_type_copy (tyty), tyty}); }; template <typename FN> void for_each_path_from_root (PlaceId var, FN fn) const @@ -413,6 +491,7 @@ private: case TyTy::PROJECTION: // TODO: DUNNO case TyTy::CLOSURE: // TODO: DUNNO case TyTy::DYNAMIC: // TODO: dunno + case TyTy::OPAQUE: return false; } rust_unreachable (); diff --git a/gcc/rust/checks/errors/borrowck/rust-bir.h b/gcc/rust/checks/errors/borrowck/rust-bir.h index ed190a0..8a5f7be 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir.h +++ b/gcc/rust/checks/errors/borrowck/rust-bir.h @@ -30,10 +30,30 @@ namespace Rust { namespace BIR { struct BasicBlock; +struct BasicBlockId; +using BasicBlocks = IndexVec<BasicBlockId, BasicBlock>; class Statement; class AbstractExpr; -using LoanId = uint32_t; +/** Unique identifier for a basic block in the BIR. */ +struct BasicBlockId +{ + uint32_t value; + // some overloads for comparision + bool operator== (const BasicBlockId &rhs) const { return value == rhs.value; } + bool operator!= (const BasicBlockId &rhs) const + { + return !(operator== (rhs)); + } + bool operator< (const BasicBlockId &rhs) const { return value < rhs.value; } + bool operator> (const BasicBlockId &rhs) const { return value > rhs.value; } + bool operator<= (const BasicBlockId &rhs) const { return !(operator> (rhs)); } + bool operator>= (const BasicBlockId &rhs) const { return !(operator< (rhs)); } +}; + +static constexpr BasicBlockId INVALID_BB + = {std::numeric_limits<uint32_t>::max ()}; +static constexpr BasicBlockId ENTRY_BASIC_BLOCK = {0}; /** * Top-level entity of the Borrow-checker IR (BIR). @@ -44,9 +64,10 @@ struct Function { PlaceDB place_db; std::vector<PlaceId> arguments; - std::vector<BasicBlock> basic_blocks; + BasicBlocks basic_blocks; FreeRegions universal_regions; std::vector<std::pair<FreeRegion, FreeRegion>> universal_region_bounds; + std::unordered_map<Polonius::Origin, HIR::LifetimeParam *> region_hir_map; location_t location; }; @@ -77,19 +98,50 @@ private: // otherwise: <unused> std::unique_ptr<AbstractExpr> expr; TyTy::BaseType *type; + // stores location of the actual expression from source code + // currently only available when kind is ASSIGNMENT | RETURN + // FIXME: Add location for other statement kinds + location_t location; public: - Statement (PlaceId lhs, AbstractExpr *rhs) - : kind (Kind::ASSIGNMENT), place (lhs), expr (rhs) - {} - - explicit Statement (Kind kind, PlaceId place = INVALID_PLACE, - AbstractExpr *expr = nullptr) - : kind (kind), place (place), expr (expr) - {} + static Statement make_assignment (PlaceId place, AbstractExpr *rhs, + location_t location) + { + return Statement (Kind::ASSIGNMENT, place, rhs, nullptr, location); + } + static Statement make_switch (PlaceId place) + { + return Statement (Kind::SWITCH, place); + } + static Statement make_return (location_t location) + { + return Statement (Kind::RETURN, INVALID_PLACE, nullptr, nullptr, location); + } + static Statement make_goto () { return Statement (Kind::GOTO); } + static Statement make_storage_dead (PlaceId place) + { + return Statement (Kind::STORAGE_DEAD, place); + } + static Statement make_storage_live (PlaceId place) + { + return Statement (Kind::STORAGE_LIVE, place); + } + static Statement make_user_type_ascription (PlaceId place, + TyTy::BaseType *type) + { + return Statement (Kind::USER_TYPE_ASCRIPTION, place, nullptr, type); + } + static Statement make_fake_read (PlaceId place) + { + return Statement (Kind::FAKE_READ, place); + } - explicit Statement (Kind kind, PlaceId place, TyTy::BaseType *type) - : kind (kind), place (place), type (type) +private: + // compelete constructor, used by make_* functions + Statement (Kind kind, PlaceId place = INVALID_PLACE, + AbstractExpr *rhs = nullptr, TyTy::BaseType *type = nullptr, + location_t location = UNKNOWN_LOCATION) + : kind (kind), place (place), expr (rhs), type (type), location (location) {} public: @@ -97,14 +149,9 @@ public: WARN_UNUSED_RESULT PlaceId get_place () const { return place; } WARN_UNUSED_RESULT AbstractExpr &get_expr () const { return *expr; } WARN_UNUSED_RESULT TyTy::BaseType *get_type () const { return type; } + WARN_UNUSED_RESULT location_t get_location () const { return location; } }; -/** Unique identifier for a basic block in the BIR. */ -using BasicBlockId = uint32_t; - -static constexpr BasicBlockId INVALID_BB - = std::numeric_limits<BasicBlockId>::max (); - struct BasicBlock { // BIR "instructions". @@ -192,7 +239,7 @@ public: loan (loan_id), origin (lifetime) {} WARN_UNUSED_RESULT PlaceId get_place () const { return place; } - WARN_UNUSED_RESULT LoanId get_loan () const { return loan; } + WARN_UNUSED_RESULT LoanId get_loan_id () const { return loan; } WARN_UNUSED_RESULT Polonius::Origin get_origin () const { return origin; } }; diff --git a/gcc/rust/checks/errors/borrowck/rust-borrow-checker-diagnostics.cc b/gcc/rust/checks/errors/borrowck/rust-borrow-checker-diagnostics.cc index a8eaa80..6c67706 100644 --- a/gcc/rust/checks/errors/borrowck/rust-borrow-checker-diagnostics.cc +++ b/gcc/rust/checks/errors/borrowck/rust-borrow-checker-diagnostics.cc @@ -17,6 +17,8 @@ // <http://www.gnu.org/licenses/>. #include "rust-borrow-checker-diagnostics.h" +#include "polonius/rust-polonius-ffi.h" +#include "rust-diagnostics.h" namespace Rust { namespace BIR { @@ -32,35 +34,136 @@ BorrowCheckerDiagnostics::report_errors () void BorrowCheckerDiagnostics::report_move_errors () { - if (!move_errors.empty ()) + for (const auto &pair : move_errors) { - rust_error_at (hir_function->get_locus (), - "Found move errors in function %s", - hir_function->get_function_name ().as_string ().c_str ()); + auto error_location = get_statement (pair.first).get_location (); + + // in future, we can use the assigned at location to hint the + // user to implement copy trait for the type + /* + for (auto it : facts.path_assigned_at_base) + { + if (pair.second[0] == it.first) + { + auto point_assigned_at = it.second; + auto assigned_at_location + = get_statement (point_assigned_at).get_location (); + } + } + */ + + std::vector<LabelLocationPair> labels{ + {"moved value used here", error_location}}; + // add labels to all the moves for the given path + for (auto it : facts.path_moved_at_base) + { + if (pair.second[0] == it.first) + { + auto point_moved_at = it.second; + // don't label the move location where the error occured + if (pair.first != point_moved_at) + { + auto move_at_location + = get_statement (point_moved_at).get_location (); + labels.push_back ({"value moved here", move_at_location}); + } + } + } + multi_label_error ("use of moved value", error_location, labels); } } void BorrowCheckerDiagnostics::report_loan_errors () { - if (!loan_errors.empty ()) + for (const auto &pair : loan_errors) { - rust_error_at (hir_function->get_locus (), - "Found loan errors in function %s", - hir_function->get_function_name ().as_string ().c_str ()); + auto error_location = get_statement (pair.first).get_location (); + for (const auto &loan : pair.second) + { + auto loan_struct = get_loan (loan); + multi_label_error ("use of borrowed value", error_location, + {{"borrow occurs here", loan_struct.location}, + {"borrowed value used here", error_location}}); + } } } void BorrowCheckerDiagnostics::report_subset_errors () { - if (!subset_errors.empty ()) + // remove duplicates in subset_errors + // + // Polonius may output subset errors for same 2 origins at multiple points + // so to avoid duplicating the errors, we can remove the elements in subset + // errors with same origin pair + std::vector<std::pair<size_t, std::pair<size_t, size_t>>> + deduplicated_subset_errors; + + for (auto pair : subset_errors) + { + auto it = std::find_if ( + deduplicated_subset_errors.begin (), deduplicated_subset_errors.end (), + [&pair] (std::pair<size_t, std::pair<size_t, size_t>> element) { + return element.second == pair.second; + }); + if (it == deduplicated_subset_errors.end ()) + { + deduplicated_subset_errors.push_back (pair); + } + } + for (const auto &error : deduplicated_subset_errors) + { + auto first_lifetime_location + = get_lifetime_param (error.second.first)->get_locus (); + auto second_lifetime_location + = get_lifetime_param (error.second.second)->get_locus (); + multi_label_error ( + "subset error, some lifetime constraints need to be added", + bir_function.location, + {{"lifetime defined here", first_lifetime_location}, + {"lifetime defined here", second_lifetime_location}, + {"subset error occurs in this function", bir_function.location}}); + } +} + +const BIR::Statement & +BorrowCheckerDiagnostics::get_statement (Polonius::Point point) +{ + auto statement_index = Polonius::FullPoint::extract_stmt (point); + auto bb_index = Polonius::FullPoint::extract_bb (point); + // assert that the extracted indexes are valid + rust_assert (bb_index < bir_function.basic_blocks.size ()); + rust_assert (statement_index + < bir_function.basic_blocks[{bb_index}].statements.size ()); + return bir_function.basic_blocks[{bb_index}].statements[statement_index]; +} + +const BIR::Loan & +BorrowCheckerDiagnostics::get_loan (Polonius::Loan loan) +{ + return bir_function.place_db.get_loans ()[{loan}]; +} + +const HIR::LifetimeParam * +BorrowCheckerDiagnostics::get_lifetime_param (Polonius::Origin origin) + +{ + return bir_function.region_hir_map.at (origin); +} + +void +BorrowCheckerDiagnostics::multi_label_error ( + const char *error_message, location_t error_location, + std::vector<LabelLocationPair> location_label_pairs) +{ + rich_location r{line_table, error_location}; + for (auto &label_location : location_label_pairs) { - rust_error_at (hir_function->get_locus (), - "Found subset errors in function %s. Some lifetime " - "constraints need to be added.", - hir_function->get_function_name ().as_string ().c_str ()); + r.add_range (label_location.location, SHOW_RANGE_WITHOUT_CARET, + &label_location.label); } + rust_error_at (r, "%s", error_message); } } // namespace BIR diff --git a/gcc/rust/checks/errors/borrowck/rust-borrow-checker-diagnostics.h b/gcc/rust/checks/errors/borrowck/rust-borrow-checker-diagnostics.h index 90d5ed8..9ab0591 100644 --- a/gcc/rust/checks/errors/borrowck/rust-borrow-checker-diagnostics.h +++ b/gcc/rust/checks/errors/borrowck/rust-borrow-checker-diagnostics.h @@ -22,6 +22,7 @@ #include "polonius/rust-polonius.h" #include "rust-bir.h" #include "rust-hir-item.h" +#include "text-range-label.h" namespace Rust { namespace BIR { @@ -62,6 +63,19 @@ private: void report_move_errors (); void report_loan_errors (); void report_subset_errors (); + + const BIR::Statement &get_statement (Polonius::Point point); + const BIR::Loan &get_loan (Polonius::Loan loan); + const HIR::LifetimeParam *get_lifetime_param (Polonius::Origin origin); + + struct LabelLocationPair + { + text_range_label label; + location_t location; + }; + static void + multi_label_error (const char *error_message, location_t error_location, + std::vector<LabelLocationPair> location_label_pairs); }; } // namespace BIR diff --git a/gcc/rust/checks/errors/borrowck/rust-function-collector.h b/gcc/rust/checks/errors/borrowck/rust-function-collector.h index 51109d7..7cf0952 100644 --- a/gcc/rust/checks/errors/borrowck/rust-function-collector.h +++ b/gcc/rust/checks/errors/borrowck/rust-function-collector.h @@ -56,13 +56,13 @@ protected: void visit (HIR::Function &function) override { functions.push_back (&function); - function.get_definition ()->accept_vis (*this); + function.get_definition ().accept_vis (*this); } void visit (HIR::ClosureExpr &closure) override { closures.push_back (&closure); - closure.get_expr ()->accept_vis (*this); + closure.get_expr ().accept_vis (*this); } // TODO: recurse for nested closures and functions. @@ -119,12 +119,11 @@ public: 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 {} void visit (HIR::InlineAsm &expr) override {} + void visit (HIR::LlvmInlineAsm &expr) override {} void visit (HIR::TypeParam ¶m) override {} void visit (HIR::ConstGenericParam ¶m) override {} void visit (HIR::LifetimeWhereClauseItem &item) override {} @@ -182,7 +181,6 @@ public: void visit (HIR::ImplTraitType &type) override {} void visit (HIR::TraitObjectType &type) override {} void visit (HIR::ParenthesisedType &type) override {} - void visit (HIR::ImplTraitTypeOneBound &type) override {} void visit (HIR::TupleType &type) override {} void visit (HIR::NeverType &type) override {} void visit (HIR::RawPointerType &type) override {} diff --git a/gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc b/gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc index d16d6ed..2a10053 100644 --- a/gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc +++ b/gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc @@ -22,6 +22,7 @@ #include "rust-hir-stmt.h" #include "rust-hir-item.h" #include "rust-attribute-values.h" +#include "rust-immutable-name-resolution-context.h" namespace Rust { namespace Privacy { @@ -93,6 +94,14 @@ static bool is_child_module (Analysis::Mappings &mappings, NodeId parent, NodeId possible_child) { + if (flag_name_resolution_2_0) + { + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); + + return nr_ctx.values.is_module_descendant (parent, possible_child); + } + auto children = mappings.lookup_module_children (parent); if (!children) @@ -118,8 +127,16 @@ PrivacyReporter::check_for_privacy_violation (const NodeId &use_id, { NodeId ref_node_id = UNKNOWN_NODEID; + if (flag_name_resolution_2_0) + { + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); + + if (auto id = nr_ctx.lookup (use_id)) + ref_node_id = *id; + } // FIXME: Don't assert here - we might be dealing with a type - if (!resolver.lookup_resolved_name (use_id, &ref_node_id)) + else if (!resolver.lookup_resolved_name (use_id, &ref_node_id)) resolver.lookup_resolved_type (use_id, &ref_node_id); // FIXME: Assert here. For now, we return since this causes issues when @@ -226,10 +243,12 @@ PrivacyReporter::check_base_type_privacy (Analysis::NodeMapping &node_mappings, static_cast<const TyTy::TupleType *> (ty)->get_fields ()) recursive_check (param.get_tyty ()); return; - case TyTy::PLACEHOLDER: - return recursive_check ( - // FIXME: Can we use `resolve` here? Is that what we should do? - static_cast<const TyTy::PlaceholderType *> (ty)->resolve ()); + case TyTy::PLACEHOLDER: { + const auto p = static_cast<const TyTy::PlaceholderType *> (ty); + if (!p->can_resolve ()) + return; + return recursive_check (p->resolve ()); + } case TyTy::PROJECTION: return recursive_check ( static_cast<const TyTy::ProjectionType *> (ty)->get ()); @@ -252,22 +271,21 @@ PrivacyReporter::check_base_type_privacy (Analysis::NodeMapping &node_mappings, // We shouldn't have inference types here, ever case TyTy::INFER: return; + case TyTy::OPAQUE: + return; case TyTy::ERROR: return; } } void -PrivacyReporter::check_type_privacy (const HIR::Type *type) +PrivacyReporter::check_type_privacy (const HIR::Type &type) { - rust_assert (type); - TyTy::BaseType *lookup = nullptr; - rust_assert ( - ty_ctx.lookup_type (type->get_mappings ().get_hirid (), &lookup)); + rust_assert (ty_ctx.lookup_type (type.get_mappings ().get_hirid (), &lookup)); - auto node_mappings = type->get_mappings (); - return check_base_type_privacy (node_mappings, lookup, type->get_locus ()); + auto node_mappings = type.get_mappings (); + return check_base_type_privacy (node_mappings, lookup, type.get_locus ()); } void @@ -284,6 +302,14 @@ PrivacyReporter::visit (HIR::TypePathSegmentFunction &) } void +PrivacyReporter::visit (HIR::InlineAsm &) +{} + +void +PrivacyReporter::visit (HIR::LlvmInlineAsm &) +{} + +void PrivacyReporter::visit (HIR::TypePath &path) { check_for_privacy_violation (path.get_mappings ().get_nodeid (), @@ -313,100 +339,98 @@ PrivacyReporter::visit (HIR::LiteralExpr &) void PrivacyReporter::visit (HIR::BorrowExpr &expr) { - expr.get_expr ()->accept_vis (*this); + expr.get_expr ().accept_vis (*this); } void PrivacyReporter::visit (HIR::DereferenceExpr &expr) { - expr.get_expr ()->accept_vis (*this); + expr.get_expr ().accept_vis (*this); } void PrivacyReporter::visit (HIR::ErrorPropagationExpr &expr) { - expr.get_expr ()->accept_vis (*this); + expr.get_expr ().accept_vis (*this); } void PrivacyReporter::visit (HIR::NegationExpr &expr) { - expr.get_expr ()->accept_vis (*this); + expr.get_expr ().accept_vis (*this); } void PrivacyReporter::visit (HIR::ArithmeticOrLogicalExpr &expr) { - expr.get_lhs ()->accept_vis (*this); - expr.get_rhs ()->accept_vis (*this); + expr.get_lhs ().accept_vis (*this); + expr.get_rhs ().accept_vis (*this); } void PrivacyReporter::visit (HIR::ComparisonExpr &expr) { - expr.get_lhs ()->accept_vis (*this); - expr.get_rhs ()->accept_vis (*this); + expr.get_lhs ().accept_vis (*this); + expr.get_rhs ().accept_vis (*this); } void PrivacyReporter::visit (HIR::LazyBooleanExpr &expr) { - expr.get_lhs ()->accept_vis (*this); - expr.get_rhs ()->accept_vis (*this); + expr.get_lhs ().accept_vis (*this); + expr.get_rhs ().accept_vis (*this); } void PrivacyReporter::visit (HIR::TypeCastExpr &expr) { - expr.get_expr ()->accept_vis (*this); + expr.get_expr ().accept_vis (*this); } void PrivacyReporter::visit (HIR::AssignmentExpr &expr) { - expr.get_lhs ()->accept_vis (*this); - expr.get_rhs ()->accept_vis (*this); + expr.get_lhs ().accept_vis (*this); + expr.get_rhs ().accept_vis (*this); } void PrivacyReporter::visit (HIR::CompoundAssignmentExpr &expr) { - expr.get_lhs ()->accept_vis (*this); - expr.get_rhs ()->accept_vis (*this); + expr.get_lhs ().accept_vis (*this); + expr.get_rhs ().accept_vis (*this); } void PrivacyReporter::visit (HIR::GroupedExpr &expr) { - expr.get_expr_in_parens ()->accept_vis (*this); + expr.get_expr_in_parens ().accept_vis (*this); } void PrivacyReporter::visit (HIR::ArrayExpr &expr) { - HIR::ArrayElems &elements = *expr.get_internal_elements (); + HIR::ArrayElems &elements = expr.get_internal_elements (); switch (elements.get_array_expr_type ()) { case HIR::ArrayElems::ArrayExprType::VALUES: { - HIR::ArrayElemsValues &elems - = static_cast<HIR::ArrayElemsValues &> (elements); + auto &elems = static_cast<HIR::ArrayElemsValues &> (elements); for (auto &value : elems.get_values ()) value->accept_vis (*this); } return; case HIR::ArrayElems::ArrayExprType::COPIED: - HIR::ArrayElemsCopied &elems - = static_cast<HIR::ArrayElemsCopied &> (elements); - elems.get_elem_to_copy ()->accept_vis (*this); + auto &elems = static_cast<HIR::ArrayElemsCopied &> (elements); + elems.get_elem_to_copy ().accept_vis (*this); } } void PrivacyReporter::visit (HIR::ArrayIndexExpr &expr) { - expr.get_array_expr ()->accept_vis (*this); - expr.get_index_expr ()->accept_vis (*this); + expr.get_array_expr ().accept_vis (*this); + expr.get_index_expr ().accept_vis (*this); } void @@ -419,7 +443,7 @@ PrivacyReporter::visit (HIR::TupleExpr &expr) void PrivacyReporter::visit (HIR::TupleIndexExpr &expr) { - expr.get_tuple_expr ()->accept_vis (*this); + expr.get_tuple_expr ().accept_vis (*this); } void @@ -435,13 +459,13 @@ PrivacyReporter::visit (HIR::StructExprFieldIdentifier &) void PrivacyReporter::visit (HIR::StructExprFieldIdentifierValue &field) { - field.get_value ()->accept_vis (*this); + field.get_value ().accept_vis (*this); } void PrivacyReporter::visit (HIR::StructExprFieldIndexValue &field) { - field.get_value ()->accept_vis (*this); + field.get_value ().accept_vis (*this); } void @@ -454,7 +478,7 @@ PrivacyReporter::visit (HIR::StructExprStructFields &expr) void PrivacyReporter::visit (HIR::CallExpr &expr) { - expr.get_fnexpr ()->accept_vis (*this); + expr.get_fnexpr ().accept_vis (*this); for (auto ¶m : expr.get_arguments ()) param->accept_vis (*this); @@ -463,7 +487,7 @@ PrivacyReporter::visit (HIR::CallExpr &expr) void PrivacyReporter::visit (HIR::MethodCallExpr &expr) { - expr.get_receiver ()->accept_vis (*this); + expr.get_receiver ().accept_vis (*this); for (auto ¶m : expr.get_arguments ()) param->accept_vis (*this); @@ -472,7 +496,7 @@ PrivacyReporter::visit (HIR::MethodCallExpr &expr) void PrivacyReporter::visit (HIR::FieldAccessExpr &expr) { - expr.get_receiver_expr ()->accept_vis (*this); + expr.get_receiver_expr ().accept_vis (*this); // FIXME: We should also check if the field is public? } @@ -489,9 +513,8 @@ PrivacyReporter::visit (HIR::BlockExpr &expr) for (auto &stmt : expr.get_statements ()) stmt->accept_vis (*this); - auto &last_expr = expr.get_final_expr (); - if (last_expr) - last_expr->accept_vis (*this); + if (expr.has_final_expr ()) + expr.get_final_expr ().accept_vis (*this); } void @@ -501,28 +524,27 @@ PrivacyReporter::visit (HIR::ContinueExpr &) void PrivacyReporter::visit (HIR::BreakExpr &expr) { - auto &break_expr = expr.get_expr (); - if (break_expr) - break_expr->accept_vis (*this); + if (expr.has_break_expr ()) + expr.get_expr ().accept_vis (*this); } void PrivacyReporter::visit (HIR::RangeFromToExpr &expr) { - expr.get_from_expr ()->accept_vis (*this); - expr.get_to_expr ()->accept_vis (*this); + expr.get_from_expr ().accept_vis (*this); + expr.get_to_expr ().accept_vis (*this); } void PrivacyReporter::visit (HIR::RangeFromExpr &expr) { - expr.get_from_expr ()->accept_vis (*this); + expr.get_from_expr ().accept_vis (*this); } void PrivacyReporter::visit (HIR::RangeToExpr &expr) { - expr.get_to_expr ()->accept_vis (*this); + expr.get_to_expr ().accept_vis (*this); } void @@ -532,8 +554,8 @@ PrivacyReporter::visit (HIR::RangeFullExpr &) void PrivacyReporter::visit (HIR::RangeFromToInclExpr &expr) { - expr.get_from_expr ()->accept_vis (*this); - expr.get_to_expr ()->accept_vis (*this); + expr.get_from_expr ().accept_vis (*this); + expr.get_to_expr ().accept_vis (*this); } void @@ -545,70 +567,55 @@ PrivacyReporter::visit (HIR::RangeToInclExpr &) void PrivacyReporter::visit (HIR::ReturnExpr &expr) { - if (expr.get_expr ()) - expr.get_expr ()->accept_vis (*this); + if (expr.has_expr ()) + expr.get_expr ().accept_vis (*this); } void PrivacyReporter::visit (HIR::UnsafeBlockExpr &expr) { - expr.get_block_expr ()->accept_vis (*this); + expr.get_block_expr ().accept_vis (*this); } void PrivacyReporter::visit (HIR::LoopExpr &expr) { - expr.get_loop_block ()->accept_vis (*this); + expr.get_loop_block ().accept_vis (*this); } void PrivacyReporter::visit (HIR::WhileLoopExpr &expr) { - expr.get_predicate_expr ()->accept_vis (*this); - expr.get_loop_block ()->accept_vis (*this); + expr.get_predicate_expr ().accept_vis (*this); + expr.get_loop_block ().accept_vis (*this); } void PrivacyReporter::visit (HIR::WhileLetLoopExpr &expr) { - expr.get_cond ()->accept_vis (*this); - expr.get_loop_block ()->accept_vis (*this); + expr.get_cond ().accept_vis (*this); + expr.get_loop_block ().accept_vis (*this); } void PrivacyReporter::visit (HIR::IfExpr &expr) { - expr.get_if_condition ()->accept_vis (*this); - expr.get_if_block ()->accept_vis (*this); + expr.get_if_condition ().accept_vis (*this); + expr.get_if_block ().accept_vis (*this); } void PrivacyReporter::visit (HIR::IfExprConseqElse &expr) { - expr.get_if_condition ()->accept_vis (*this); - expr.get_if_block ()->accept_vis (*this); - expr.get_else_block ()->accept_vis (*this); -} - -void -PrivacyReporter::visit (HIR::IfLetExpr &) -{ - // TODO: We need to visit the if_let_expr - // TODO: We need to visit the block as well -} - -void -PrivacyReporter::visit (HIR::IfLetExprConseqElse &) -{ - // TODO: We need to visit the if_let_expr - // TODO: We need to visit the if_block as well - // TODO: We need to visit the else_block as well + expr.get_if_condition ().accept_vis (*this); + expr.get_if_block ().accept_vis (*this); + expr.get_else_block ().accept_vis (*this); } void PrivacyReporter::visit (HIR::MatchExpr &expr) { - expr.get_scrutinee_expr ()->accept_vis (*this); + expr.get_scrutinee_expr ().accept_vis (*this); } void @@ -651,9 +658,9 @@ void PrivacyReporter::visit (HIR::Function &function) { for (auto ¶m : function.get_function_params ()) - check_type_privacy (param.get_type ().get ()); + check_type_privacy (param.get_type ()); - function.get_definition ()->accept_vis (*this); + function.get_definition ().accept_vis (*this); } void @@ -710,14 +717,14 @@ void PrivacyReporter::visit (HIR::ConstantItem &const_item) { // TODO: We need to visit the type - const_item.get_expr ()->accept_vis (*this); + const_item.get_expr ().accept_vis (*this); } void PrivacyReporter::visit (HIR::StaticItem &static_item) { // TODO: We need to visit the type - static_item.get_expr ()->accept_vis (*this); + static_item.get_expr ().accept_vis (*this); } void @@ -750,17 +757,17 @@ PrivacyReporter::visit (HIR::EmptyStmt &) void PrivacyReporter::visit (HIR::LetStmt &stmt) { - if (stmt.get_type ()) - check_type_privacy (stmt.get_type ().get ()); + if (stmt.has_type ()) + check_type_privacy (stmt.get_type ()); - if (stmt.get_init_expr ()) - stmt.get_init_expr ()->accept_vis (*this); + if (stmt.has_init_expr ()) + stmt.get_init_expr ().accept_vis (*this); } void PrivacyReporter::visit (HIR::ExprStmt &stmt) { - stmt.get_expr ()->accept_vis (*this); + stmt.get_expr ().accept_vis (*this); } } // namespace Privacy diff --git a/gcc/rust/checks/errors/privacy/rust-privacy-reporter.h b/gcc/rust/checks/errors/privacy/rust-privacy-reporter.h index 6f2937c..7df2cf4 100644 --- a/gcc/rust/checks/errors/privacy/rust-privacy-reporter.h +++ b/gcc/rust/checks/errors/privacy/rust-privacy-reporter.h @@ -75,7 +75,7 @@ types * @param type Reference to an explicit type used in a statement, expression * or parameter */ - void check_type_privacy (const HIR::Type *type); + void check_type_privacy (const HIR::Type &type); virtual void visit (HIR::StructExprFieldIdentifier &field); virtual void visit (HIR::StructExprFieldIdentifierValue &field); @@ -121,11 +121,11 @@ types virtual void visit (HIR::WhileLetLoopExpr &expr); virtual void visit (HIR::IfExpr &expr); virtual void visit (HIR::IfExprConseqElse &expr); - virtual void visit (HIR::IfLetExpr &expr); - virtual void visit (HIR::IfLetExprConseqElse &expr); virtual void visit (HIR::MatchExpr &expr); virtual void visit (HIR::AwaitExpr &expr); virtual void visit (HIR::AsyncBlockExpr &expr); + virtual void visit (HIR::InlineAsm &expr); + virtual void visit (HIR::LlvmInlineAsm &expr); virtual void visit (HIR::EnumItemTuple &); virtual void visit (HIR::EnumItemStruct &); diff --git a/gcc/rust/checks/errors/privacy/rust-reachability.cc b/gcc/rust/checks/errors/privacy/rust-reachability.cc index 9e0cb82..1e57674 100644 --- a/gcc/rust/checks/errors/privacy/rust-reachability.cc +++ b/gcc/rust/checks/errors/privacy/rust-reachability.cc @@ -132,7 +132,7 @@ ReachabilityVisitor::visit (HIR::StructStruct &struct_item) { for (auto &field : struct_item.get_fields ()) if (field.get_visibility ().is_public ()) - ctx.update_reachability (field.get_field_type ()->get_mappings (), + ctx.update_reachability (field.get_field_type ().get_mappings (), struct_reach); } diff --git a/gcc/rust/checks/errors/privacy/rust-visibility-resolver.cc b/gcc/rust/checks/errors/privacy/rust-visibility-resolver.cc index 464ce86..f0da745 100644 --- a/gcc/rust/checks/errors/privacy/rust-visibility-resolver.cc +++ b/gcc/rust/checks/errors/privacy/rust-visibility-resolver.cc @@ -20,6 +20,10 @@ #include "rust-ast.h" #include "rust-hir.h" #include "rust-hir-item.h" +#include "rust-immutable-name-resolution-context.h" + +// for flag_name_resolution_2_0 +#include "options.h" namespace Rust { namespace Privacy { @@ -61,7 +65,22 @@ VisibilityResolver::resolve_module_path (const HIR::SimplePath &restriction, "cannot use non-module path as privacy restrictor"); NodeId ref_node_id = UNKNOWN_NODEID; - if (!resolver.lookup_resolved_name (ast_node_id, &ref_node_id)) + if (flag_name_resolution_2_0) + { + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); + + if (auto id = nr_ctx.lookup (ast_node_id)) + { + ref_node_id = *id; + } + else + { + invalid_path.emit (); + return false; + } + } + else if (!resolver.lookup_resolved_name (ast_node_id, &ref_node_id)) { invalid_path.emit (); return false; diff --git a/gcc/rust/checks/errors/rust-ast-validation.cc b/gcc/rust/checks/errors/rust-ast-validation.cc index 7938286..0f4bdeb 100644 --- a/gcc/rust/checks/errors/rust-ast-validation.cc +++ b/gcc/rust/checks/errors/rust-ast-validation.cc @@ -56,7 +56,7 @@ ASTValidation::visit (AST::LoopLabel &label) void ASTValidation::visit (AST::ConstantItem &const_item) { - if (!const_item.has_expr () && context.back () != Context::TRAIT_IMPL) + if (!const_item.has_expr () && ctx.peek () != Kind::TRAIT) { rust_error_at (const_item.get_locus (), "associated constant in %<impl%> without body"); @@ -82,23 +82,19 @@ ASTValidation::visit (AST::Function &function) "functions cannot be both %<const%> and %<async%>"); if (qualifiers.is_const () - && (context.back () == Context::TRAIT_IMPL - || context.back () == Context::TRAIT)) + && (ctx.peek () == Kind::TRAIT_IMPL || ctx.peek () == Kind::TRAIT)) rust_error_at (function.get_locus (), ErrorCode::E0379, "functions in traits cannot be declared %<const%>"); // may change soon if (qualifiers.is_async () - && (context.back () == Context::TRAIT_IMPL - || context.back () == Context::TRAIT)) + && (ctx.peek () == Kind::TRAIT_IMPL || ctx.peek () == Kind::TRAIT)) rust_error_at (function.get_locus (), ErrorCode::E0706, "functions in traits cannot be declared %<async%>"); // if not an associated function but has a self parameter - if (context.back () != Context::TRAIT - && context.back () != Context::TRAIT_IMPL - && context.back () != Context::INHERENT_IMPL - && function.has_self_param ()) + if (ctx.peek () != Kind::TRAIT && ctx.peek () != Kind::TRAIT_IMPL + && ctx.peek () != Kind::INHERENT_IMPL && function.has_self_param ()) rust_error_at ( function.get_self_param ().get_locus (), "%<self%> parameter is only allowed in associated functions"); @@ -140,11 +136,11 @@ ASTValidation::visit (AST::Function &function) { if (!function.has_body ()) { - if (context.back () == Context::INHERENT_IMPL - || context.back () == Context::TRAIT_IMPL) + if (ctx.peek () == Kind::INHERENT_IMPL + || ctx.peek () == Kind::TRAIT_IMPL) rust_error_at (function.get_locus (), "associated function in %<impl%> without body"); - else if (context.back () != Context::TRAIT) + else if (ctx.peek () != Kind::TRAIT) rust_error_at (function.get_locus (), "free function without a body"); } diff --git a/gcc/rust/checks/errors/rust-const-checker.cc b/gcc/rust/checks/errors/rust-const-checker.cc index 2beee21..3716ea5 100644 --- a/gcc/rust/checks/errors/rust-const-checker.cc +++ b/gcc/rust/checks/errors/rust-const-checker.cc @@ -22,6 +22,10 @@ #include "rust-hir-stmt.h" #include "rust-hir-item.h" #include "rust-system.h" +#include "rust-immutable-name-resolution-context.h" + +// for flag_name_resolution_2_0 +#include "options.h" namespace Rust { namespace HIR { @@ -157,72 +161,72 @@ ConstChecker::visit (LiteralExpr &) void ConstChecker::visit (BorrowExpr &expr) { - expr.get_expr ()->accept_vis (*this); + expr.get_expr ().accept_vis (*this); } void ConstChecker::visit (DereferenceExpr &expr) { - expr.get_expr ()->accept_vis (*this); + expr.get_expr ().accept_vis (*this); } void ConstChecker::visit (ErrorPropagationExpr &expr) { - expr.get_expr ()->accept_vis (*this); + expr.get_expr ().accept_vis (*this); } void ConstChecker::visit (NegationExpr &expr) { - expr.get_expr ()->accept_vis (*this); + expr.get_expr ().accept_vis (*this); } void ConstChecker::visit (ArithmeticOrLogicalExpr &expr) { - expr.get_lhs ()->accept_vis (*this); - expr.get_rhs ()->accept_vis (*this); + expr.get_lhs ().accept_vis (*this); + expr.get_rhs ().accept_vis (*this); } void ConstChecker::visit (ComparisonExpr &expr) { - expr.get_lhs ()->accept_vis (*this); - expr.get_rhs ()->accept_vis (*this); + expr.get_lhs ().accept_vis (*this); + expr.get_rhs ().accept_vis (*this); } void ConstChecker::visit (LazyBooleanExpr &expr) { - expr.get_lhs ()->accept_vis (*this); - expr.get_rhs ()->accept_vis (*this); + expr.get_lhs ().accept_vis (*this); + expr.get_rhs ().accept_vis (*this); } void ConstChecker::visit (TypeCastExpr &expr) { - expr.get_expr ()->accept_vis (*this); + expr.get_expr ().accept_vis (*this); } void ConstChecker::visit (AssignmentExpr &expr) { - expr.get_lhs ()->accept_vis (*this); - expr.get_rhs ()->accept_vis (*this); + expr.get_lhs ().accept_vis (*this); + expr.get_rhs ().accept_vis (*this); } void ConstChecker::visit (CompoundAssignmentExpr &expr) { - expr.get_lhs ()->accept_vis (*this); - expr.get_rhs ()->accept_vis (*this); + expr.get_lhs ().accept_vis (*this); + expr.get_rhs ().accept_vis (*this); } void ConstChecker::visit (GroupedExpr &expr) { - expr.get_expr_in_parens ()->accept_vis (*this); + expr.get_expr_in_parens ().accept_vis (*this); } void @@ -235,11 +239,11 @@ ConstChecker::visit (ArrayElemsValues &elems) void ConstChecker::visit (ArrayElemsCopied &elems) { - elems.get_elem_to_copy ()->accept_vis (*this); + elems.get_elem_to_copy ().accept_vis (*this); const_context.enter (elems.get_mappings ().get_hirid ()); - elems.get_num_copies_expr ()->accept_vis (*this); + elems.get_num_copies_expr ().accept_vis (*this); const_context.exit (); } @@ -247,14 +251,14 @@ ConstChecker::visit (ArrayElemsCopied &elems) void ConstChecker::visit (ArrayExpr &expr) { - expr.get_internal_elements ()->accept_vis (*this); + expr.get_internal_elements ().accept_vis (*this); } void ConstChecker::visit (ArrayIndexExpr &expr) { - expr.get_array_expr ()->accept_vis (*this); - expr.get_index_expr ()->accept_vis (*this); + expr.get_array_expr ().accept_vis (*this); + expr.get_index_expr ().accept_vis (*this); } void @@ -267,7 +271,7 @@ ConstChecker::visit (TupleExpr &expr) void ConstChecker::visit (TupleIndexExpr &expr) { - expr.get_tuple_expr ()->accept_vis (*this); + expr.get_tuple_expr ().accept_vis (*this); } void @@ -281,13 +285,13 @@ ConstChecker::visit (StructExprFieldIdentifier &) void ConstChecker::visit (StructExprFieldIdentifierValue &field) { - field.get_value ()->accept_vis (*this); + field.get_value ().accept_vis (*this); } void ConstChecker::visit (StructExprFieldIndexValue &field) { - field.get_value ()->accept_vis (*this); + field.get_value ().accept_vis (*this); } void @@ -348,14 +352,24 @@ ConstChecker::check_function_call (HirId fn_id, location_t locus) void ConstChecker::visit (CallExpr &expr) { - if (!expr.get_fnexpr ()) + if (!expr.has_fnexpr ()) return; - NodeId ast_node_id = expr.get_fnexpr ()->get_mappings ().get_nodeid (); + NodeId ast_node_id = expr.get_fnexpr ().get_mappings ().get_nodeid (); NodeId ref_node_id; + if (flag_name_resolution_2_0) + { + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); + + if (auto id = nr_ctx.lookup (ast_node_id)) + ref_node_id = *id; + else + return; + } // We don't care about types here - if (!resolver.lookup_resolved_name (ast_node_id, &ref_node_id)) + else if (!resolver.lookup_resolved_name (ast_node_id, &ref_node_id)) return; if (auto definition_id = mappings.lookup_node_to_hir (ref_node_id)) @@ -374,7 +388,7 @@ ConstChecker::visit (CallExpr &expr) void ConstChecker::visit (MethodCallExpr &expr) { - expr.get_receiver ()->accept_vis (*this); + expr.get_receiver ().accept_vis (*this); for (auto &arg : expr.get_arguments ()) arg->accept_vis (*this); @@ -383,13 +397,13 @@ ConstChecker::visit (MethodCallExpr &expr) void ConstChecker::visit (FieldAccessExpr &expr) { - expr.get_receiver_expr ()->accept_vis (*this); + expr.get_receiver_expr ().accept_vis (*this); } void ConstChecker::visit (ClosureExpr &expr) { - expr.get_expr ()->accept_vis (*this); + expr.get_expr ().accept_vis (*this); } void @@ -399,7 +413,7 @@ ConstChecker::visit (BlockExpr &expr) stmt->accept_vis (*this); if (expr.has_expr ()) - expr.get_final_expr ()->accept_vis (*this); + expr.get_final_expr ().accept_vis (*this); } void @@ -410,26 +424,26 @@ void ConstChecker::visit (BreakExpr &expr) { if (expr.has_break_expr ()) - expr.get_expr ()->accept_vis (*this); + expr.get_expr ().accept_vis (*this); } void ConstChecker::visit (RangeFromToExpr &expr) { - expr.get_from_expr ()->accept_vis (*this); - expr.get_to_expr ()->accept_vis (*this); + expr.get_from_expr ().accept_vis (*this); + expr.get_to_expr ().accept_vis (*this); } void ConstChecker::visit (RangeFromExpr &expr) { - expr.get_from_expr ()->accept_vis (*this); + expr.get_from_expr ().accept_vis (*this); } void ConstChecker::visit (RangeToExpr &expr) { - expr.get_to_expr ()->accept_vis (*this); + expr.get_to_expr ().accept_vis (*this); } void @@ -439,8 +453,8 @@ ConstChecker::visit (RangeFullExpr &) void ConstChecker::visit (RangeFromToInclExpr &expr) { - expr.get_from_expr ()->accept_vis (*this); - expr.get_to_expr ()->accept_vis (*this); + expr.get_from_expr ().accept_vis (*this); + expr.get_to_expr ().accept_vis (*this); } void @@ -453,73 +467,57 @@ void ConstChecker::visit (ReturnExpr &expr) { if (expr.has_return_expr ()) - expr.get_expr ()->accept_vis (*this); + expr.get_expr ().accept_vis (*this); } void ConstChecker::visit (UnsafeBlockExpr &expr) { - expr.get_block_expr ()->accept_vis (*this); + expr.get_block_expr ().accept_vis (*this); } void ConstChecker::visit (LoopExpr &expr) { - expr.get_loop_block ()->accept_vis (*this); + expr.get_loop_block ().accept_vis (*this); } void ConstChecker::visit (WhileLoopExpr &expr) { - expr.get_predicate_expr ()->accept_vis (*this); - expr.get_loop_block ()->accept_vis (*this); + expr.get_predicate_expr ().accept_vis (*this); + expr.get_loop_block ().accept_vis (*this); } void ConstChecker::visit (WhileLetLoopExpr &expr) { - expr.get_cond ()->accept_vis (*this); - expr.get_loop_block ()->accept_vis (*this); + expr.get_cond ().accept_vis (*this); + expr.get_loop_block ().accept_vis (*this); } void ConstChecker::visit (IfExpr &expr) { - expr.get_if_condition ()->accept_vis (*this); - expr.get_if_block ()->accept_vis (*this); + expr.get_if_condition ().accept_vis (*this); + expr.get_if_block ().accept_vis (*this); } void ConstChecker::visit (IfExprConseqElse &expr) { - expr.get_if_condition ()->accept_vis (*this); - expr.get_if_block ()->accept_vis (*this); - expr.get_else_block ()->accept_vis (*this); -} - -void -ConstChecker::visit (IfLetExpr &expr) -{ - expr.get_scrutinee_expr ()->accept_vis (*this); - expr.get_if_block ()->accept_vis (*this); -} - -void -ConstChecker::visit (IfLetExprConseqElse &expr) -{ - expr.get_scrutinee_expr ()->accept_vis (*this); - expr.get_if_block ()->accept_vis (*this); - - // TODO: Visit else expression + expr.get_if_condition ().accept_vis (*this); + expr.get_if_block ().accept_vis (*this); + expr.get_else_block ().accept_vis (*this); } void ConstChecker::visit (MatchExpr &expr) { - expr.get_scrutinee_expr ()->accept_vis (*this); + expr.get_scrutinee_expr ().accept_vis (*this); for (auto &match_arm : expr.get_match_cases ()) - match_arm.get_expr ()->accept_vis (*this); + match_arm.get_expr ().accept_vis (*this); } void @@ -539,6 +537,10 @@ ConstChecker::visit (InlineAsm &) {} void +ConstChecker::visit (LlvmInlineAsm &) +{} + +void ConstChecker::visit (TypeParam &) {} @@ -592,9 +594,9 @@ ConstChecker::visit (Function &function) ConstGenericCtx::Function); for (auto ¶m : function.get_function_params ()) - param.get_type ()->accept_vis (*this); + param.get_type ().accept_vis (*this); - function.get_definition ()->accept_vis (*this); + function.get_definition ().accept_vis (*this); if (const_fn) const_context.exit (); @@ -638,7 +640,7 @@ ConstChecker::visit (EnumItemDiscriminant &item) { const_context.enter (item.get_mappings ().get_hirid ()); - item.get_discriminant_expression ()->accept_vis (*this); + item.get_discriminant_expression ().accept_vis (*this); const_context.exit (); } @@ -648,6 +650,9 @@ ConstChecker::visit (Enum &enum_item) { check_default_const_generics (enum_item.get_generic_params (), ConstGenericCtx::Enum); + + for (auto &item : enum_item.get_variants ()) + item->accept_vis (*this); } void @@ -662,7 +667,7 @@ ConstChecker::visit (ConstantItem &const_item) { const_context.enter (const_item.get_mappings ().get_hirid ()); - const_item.get_expr ()->accept_vis (*this); + const_item.get_expr ().accept_vis (*this); const_context.exit (); } @@ -672,7 +677,7 @@ ConstChecker::visit (StaticItem &static_item) { const_context.enter (static_item.get_mappings ().get_hirid ()); - static_item.get_expr ()->accept_vis (*this); + static_item.get_expr ().accept_vis (*this); const_context.exit (); } @@ -680,15 +685,15 @@ ConstChecker::visit (StaticItem &static_item) void ConstChecker::visit (TraitItemFunc &item) { - if (item.has_block_defined ()) - item.get_block_expr ()->accept_vis (*this); + if (item.has_definition ()) + item.get_block_expr ().accept_vis (*this); } void ConstChecker::visit (TraitItemConst &item) { if (item.has_expr ()) - item.get_expr ()->accept_vis (*this); + item.get_expr ().accept_vis (*this); } void @@ -823,13 +828,13 @@ void ConstChecker::visit (LetStmt &stmt) { if (stmt.has_init_expr ()) - stmt.get_init_expr ()->accept_vis (*this); + stmt.get_init_expr ().accept_vis (*this); } void ConstChecker::visit (ExprStmt &stmt) { - stmt.get_expr ()->accept_vis (*this); + stmt.get_expr ().accept_vis (*this); } void @@ -849,10 +854,6 @@ ConstChecker::visit (ParenthesisedType &) {} void -ConstChecker::visit (ImplTraitTypeOneBound &) -{} - -void ConstChecker::visit (TupleType &) {} @@ -877,7 +878,7 @@ ConstChecker::visit (ArrayType &type) { const_context.enter (type.get_mappings ().get_hirid ()); - type.get_size_expr ()->accept_vis (*this); + type.get_size_expr ().accept_vis (*this); const_context.exit (); } diff --git a/gcc/rust/checks/errors/rust-const-checker.h b/gcc/rust/checks/errors/rust-const-checker.h index 8890761..b954330 100644 --- a/gcc/rust/checks/errors/rust-const-checker.h +++ b/gcc/rust/checks/errors/rust-const-checker.h @@ -128,12 +128,11 @@ private: virtual void visit (WhileLetLoopExpr &expr) override; virtual void visit (IfExpr &expr) override; virtual void visit (IfExprConseqElse &expr) override; - virtual void visit (IfLetExpr &expr) override; - virtual void visit (IfLetExprConseqElse &expr) override; virtual void visit (MatchExpr &expr) override; virtual void visit (AwaitExpr &expr) override; virtual void visit (AsyncBlockExpr &expr) override; virtual void visit (InlineAsm &expr) override; + virtual void visit (LlvmInlineAsm &expr) override; virtual void visit (TypeParam ¶m) override; virtual void visit (ConstGenericParam ¶m) override; @@ -193,7 +192,6 @@ private: virtual void visit (ImplTraitType &type) override; virtual void visit (TraitObjectType &type) override; virtual void visit (ParenthesisedType &type) override; - virtual void visit (ImplTraitTypeOneBound &type) override; virtual void visit (TupleType &type) override; virtual void visit (NeverType &type) override; virtual void visit (RawPointerType &type) override; diff --git a/gcc/rust/checks/errors/rust-feature-gate.cc b/gcc/rust/checks/errors/rust-feature-gate.cc index 580afc9..44007f9 100644 --- a/gcc/rust/checks/errors/rust-feature-gate.cc +++ b/gcc/rust/checks/errors/rust-feature-gate.cc @@ -21,6 +21,7 @@ #include "rust-attribute-values.h" #include "rust-ast-visitor.h" #include "rust-feature.h" +#include "rust-ast-full.h" namespace Rust { @@ -39,6 +40,13 @@ FeatureGate::visit (AST::Crate &crate) { if (attr.get_path ().as_string () == "feature") { + // check for empty feature, such as `#![feature], this is an error + if (attr.empty_input ()) + { + rust_error_at (attr.get_locus (), ErrorCode::E0556, + "malformed %<feature%> attribute input"); + continue; + } const auto &attr_input = attr.get_attr_input (); auto type = attr_input.get_attr_input_type (); if (type == AST::AttrInput::AttrInputType::TOKEN_TREE) @@ -75,16 +83,17 @@ FeatureGate::gate (Feature::Name name, location_t loc, if (!valid_features.count (name)) { auto feature = Feature::create (name); - auto issue = feature.issue (); - if (issue > 0) + if (auto issue = feature.issue ()) { + auto issue_number = issue.value (); const char *fmt_str = "%s. see issue %u " "<https://github.com/rust-lang/rust/issues/%u> for more " "information. add `#![feature(%s)]` to the crate attributes to " "enable."; rust_error_at (loc, ErrorCode::E0658, fmt_str, error_msg.c_str (), - issue, issue, feature.as_string ().c_str ()); + issue_number, issue_number, + feature.as_string ().c_str ()); } else { @@ -169,7 +178,16 @@ FeatureGate::visit (AST::TraitImpl &impl) "negative_impls are not yet implemented"); AST::DefaultASTVisitor::visit (impl); -}; +} + +void +FeatureGate::visit (AST::Trait &trait) +{ + if (trait.is_auto ()) + gate (Feature::Name::AUTO_TRAITS, trait.get_locus (), + "auto traits are experimental and possibly buggy"); + AST::DefaultASTVisitor::visit (trait); +} void FeatureGate::visit (AST::BoxExpr &expr) @@ -217,4 +235,12 @@ FeatureGate::visit (AST::RangePattern &pattern) "exclusive range pattern syntax is experimental"); } +void +FeatureGate::visit (AST::UseTreeGlob &use) +{ + // At the moment, UseTrees do not have outer attributes, but they should. we + // need to eventually gate `#[prelude_import]` on use-trees based on the + // #[feature(prelude_import)] +} + } // namespace Rust diff --git a/gcc/rust/checks/errors/rust-feature-gate.h b/gcc/rust/checks/errors/rust-feature-gate.h index 31c2ed6..f1011e5 100644 --- a/gcc/rust/checks/errors/rust-feature-gate.h +++ b/gcc/rust/checks/errors/rust-feature-gate.h @@ -20,7 +20,6 @@ #define RUST_FEATURE_GATE_H #include "rust-ast-visitor.h" -#include "rust-ast-full.h" #include "rust-feature.h" namespace Rust { @@ -35,153 +34,19 @@ public: void check (AST::Crate &crate); void visit (AST::Crate &crate) override; - void visit (AST::Token &tok) override {} - void visit (AST::DelimTokenTree &delim_tok_tree) override {} - void visit (AST::AttrInputMetaItemContainer &input) override {} - void visit (AST::IdentifierExpr &ident_expr) override {} - void visit (AST::Lifetime &lifetime) override {} void visit (AST::LifetimeParam &lifetime_param) override; void visit (AST::ConstGenericParam &const_param) override; - void visit (AST::PathInExpression &path) override {} - void visit (AST::TypePathSegment &segment) override {} - void visit (AST::TypePathSegmentGeneric &segment) override {} - void visit (AST::TypePathSegmentFunction &segment) override {} - void visit (AST::TypePath &path) override {} - void visit (AST::QualifiedPathInExpression &path) override {} - void visit (AST::QualifiedPathInType &path) override {} - void visit (AST::LiteralExpr &expr) override {} - void visit (AST::AttrInputLiteral &attr_input) override {} - void visit (AST::AttrInputMacro &attr_input) override {} - void visit (AST::MetaItemLitExpr &meta_item) override {} - void visit (AST::MetaItemPathLit &meta_item) override {} void visit (AST::BorrowExpr &expr) override; - void visit (AST::DereferenceExpr &expr) override {} - void visit (AST::ErrorPropagationExpr &expr) override {} - void visit (AST::NegationExpr &expr) override {} - void visit (AST::ArithmeticOrLogicalExpr &expr) override {} - void visit (AST::ComparisonExpr &expr) override {} - void visit (AST::LazyBooleanExpr &expr) override {} - void visit (AST::TypeCastExpr &expr) override {} - void visit (AST::AssignmentExpr &expr) override {} - void visit (AST::CompoundAssignmentExpr &expr) override {} - void visit (AST::GroupedExpr &expr) override {} - void visit (AST::ArrayElemsValues &elems) override {} - void visit (AST::ArrayElemsCopied &elems) override {} - void visit (AST::ArrayExpr &expr) override {} - void visit (AST::ArrayIndexExpr &expr) override {} - void visit (AST::TupleExpr &expr) override {} - void visit (AST::TupleIndexExpr &expr) override {} - void visit (AST::StructExprStruct &expr) override {} - void visit (AST::StructExprFieldIdentifier &field) override {} - void visit (AST::StructExprFieldIdentifierValue &field) override {} - void visit (AST::StructExprFieldIndexValue &field) override {} - void visit (AST::StructExprStructFields &expr) override {} - void visit (AST::StructExprStructBase &expr) override {} - void visit (AST::CallExpr &expr) override {} - void visit (AST::MethodCallExpr &expr) override {} - void visit (AST::FieldAccessExpr &expr) override {} - void visit (AST::ClosureExprInner &expr) override {} - void visit (AST::ClosureExprInnerTyped &expr) override {} - void visit (AST::ContinueExpr &expr) override {} - void visit (AST::BreakExpr &expr) override {} - void visit (AST::RangeFromToExpr &expr) override {} - void visit (AST::RangeFromExpr &expr) override {} - void visit (AST::RangeToExpr &expr) override {} - void visit (AST::RangeFullExpr &expr) override {} - void visit (AST::RangeFromToInclExpr &expr) override {} - void visit (AST::RangeToInclExpr &expr) override {} - void visit (AST::ReturnExpr &expr) override {} void visit (AST::BoxExpr &expr) override; - void visit (AST::UnsafeBlockExpr &expr) override {} - void visit (AST::LoopExpr &expr) override {} - void visit (AST::WhileLoopExpr &expr) override {} - void visit (AST::WhileLetLoopExpr &expr) override {} - void visit (AST::ForLoopExpr &expr) override {} - void visit (AST::IfExpr &expr) override {} - void visit (AST::IfExprConseqElse &expr) override {} - void visit (AST::IfLetExprConseqElse &expr) override {} - void visit (AST::AwaitExpr &expr) override {} - void visit (AST::AsyncBlockExpr &expr) override {} void visit (AST::TypeParam ¶m) override; - void visit (AST::LifetimeWhereClauseItem &item) override {} - void visit (AST::TypeBoundWhereClauseItem &item) override {} - void visit (AST::Module &module) override {} - void visit (AST::ExternCrate &crate) override {} - void visit (AST::UseTreeGlob &use_tree) override {} - void visit (AST::UseTreeList &use_tree) override {} - void visit (AST::UseTreeRebind &use_tree) override {} - void visit (AST::UseDeclaration &use_decl) override {} + void visit (AST::UseTreeGlob &use_tree) override; void visit (AST::Function &function) override; - void visit (AST::TypeAlias &type_alias) override {} - void visit (AST::StructStruct &struct_item) override {} - void visit (AST::TupleStruct &tuple_struct) override {} - void visit (AST::EnumItem &item) override {} - void visit (AST::EnumItemTuple &item) override {} - void visit (AST::EnumItemStruct &item) override {} - void visit (AST::EnumItemDiscriminant &item) override {} - void visit (AST::Enum &enum_item) override {} - void visit (AST::Union &union_item) override {} - void visit (AST::ConstantItem &const_item) override {} - void visit (AST::StaticItem &static_item) override {} - void visit (AST::TraitItemConst &item) override {} - void visit (AST::TraitItemType &item) override {} void visit (AST::TraitImpl &impl) override; - void visit (AST::Trait &trait) override {} + void visit (AST::Trait &trait) override; void visit (AST::ExternalTypeItem &item) override; - void visit (AST::ExternalStaticItem &item) override {} void visit (AST::ExternBlock &block) override; - void visit (AST::MacroMatchFragment &match) override {} - void visit (AST::MacroMatchRepetition &match) override {} - void visit (AST::MacroMatcher &matcher) override {} void visit (AST::MacroRulesDefinition &rules_def) override; - void visit (AST::MacroInvocation ¯o_invoc) override {} - void visit (AST::MetaItemPath &meta_item) override {} - void visit (AST::MetaItemSeq &meta_item) override {} - void visit (AST::MetaWord &meta_item) override {} - void visit (AST::MetaNameValueStr &meta_item) override {} - void visit (AST::MetaListPaths &meta_item) override {} - void visit (AST::MetaListNameValueStr &meta_item) override {} - void visit (AST::LiteralPattern &pattern) override {} - void visit (AST::IdentifierPattern &pattern) override {} - void visit (AST::WildcardPattern &pattern) override {} - void visit (AST::RestPattern &pattern) override {} - void visit (AST::RangePatternBoundLiteral &bound) override {} - void visit (AST::RangePatternBoundPath &bound) override {} - void visit (AST::RangePatternBoundQualPath &bound) override {} void visit (AST::RangePattern &pattern) override; - void visit (AST::ReferencePattern &pattern) override {} - void visit (AST::StructPatternFieldTuplePat &field) override {} - void visit (AST::StructPatternFieldIdentPat &field) override {} - void visit (AST::StructPatternFieldIdent &field) override {} - void visit (AST::StructPattern &pattern) override {} - void visit (AST::TupleStructItemsNoRange &tuple_items) override {} - void visit (AST::TupleStructItemsRange &tuple_items) override {} - void visit (AST::TupleStructPattern &pattern) override {} - void visit (AST::TuplePatternItemsMultiple &tuple_items) override {} - void visit (AST::TuplePatternItemsRanged &tuple_items) override {} - void visit (AST::TuplePattern &pattern) override {} - void visit (AST::GroupedPattern &pattern) override {} - void visit (AST::SlicePattern &pattern) override {} - void visit (AST::AltPattern &pattern) override {} - void visit (AST::EmptyStmt &stmt) override {} - void visit (AST::ExprStmt &stmt) override {} - void visit (AST::TraitBound &bound) override {} - void visit (AST::ImplTraitType &type) override {} - void visit (AST::TraitObjectType &type) override {} - void visit (AST::ParenthesisedType &type) override {} - void visit (AST::ImplTraitTypeOneBound &type) override {} - void visit (AST::TraitObjectTypeOneBound &type) override {} - void visit (AST::TupleType &type) override {} - void visit (AST::NeverType &type) override {} - void visit (AST::RawPointerType &type) override {} - void visit (AST::ReferenceType &type) override {} - void visit (AST::ArrayType &type) override {} - void visit (AST::SliceType &type) override {} - void visit (AST::InferredType &type) override {} - void visit (AST::BareFunctionType &type) override {} - void visit (AST::FunctionParam ¶m) override {} - void visit (AST::VariadicParam ¶m) override {} - void visit (AST::SelfParam ¶m) override {} private: void gate (Feature::Name name, location_t loc, const std::string &error_msg); diff --git a/gcc/rust/checks/errors/rust-feature.cc b/gcc/rust/checks/errors/rust-feature.cc index 917e3b2..441a1b2 100644 --- a/gcc/rust/checks/errors/rust-feature.cc +++ b/gcc/rust/checks/errors/rust-feature.cc @@ -17,47 +17,50 @@ // <http://www.gnu.org/licenses/>. #include "rust-feature.h" -#include "rust-session-manager.h" namespace Rust { Feature -Feature::create (Feature::Name name) +Feature::create (Feature::Name f) { - switch (name) + switch (f) { case Feature::Name::ASSOCIATED_TYPE_BOUNDS: return Feature (Feature::Name::ASSOCIATED_TYPE_BOUNDS, Feature::State::ACCEPTED, "associated_type_bounds", - "1.34.0", 52662, tl::nullopt, ""); + "1.34.0", 52662); case Feature::Name::INTRINSICS: - return Feature (Feature::Name::INTRINSICS, Feature::State::ACCEPTED, - "intrinsics", "1.0.0", 0, tl::nullopt, ""); + return Feature (f, Feature::State::ACCEPTED, "intrinsics", "1.0.0"); case Feature::Name::RUSTC_ATTRS: - return Feature (Feature::Name::RUSTC_ATTRS, Feature::State::ACCEPTED, - "rustc_attrs", "1.0.0", 0, tl::nullopt, ""); + return Feature (f, Feature::State::ACCEPTED, "rustc_attrs", "1.0.0"); case Feature::Name::DECL_MACRO: - return Feature (Feature::Name::DECL_MACRO, Feature::State::ACCEPTED, - "decl_macro", "1.0.0", 0, tl::nullopt, ""); + return Feature (f, Feature::State::ACCEPTED, "decl_macro", "1.0.0", + 39412); case Feature::Name::EXTERN_TYPES: - return Feature (Feature::Name::EXTERN_TYPES, Feature::State::ACTIVE, - "extern_types", "1.23.0", 43467, tl::nullopt, ""); + return Feature (f, Feature::State::ACTIVE, "extern_types", "1.23.0", + 43467); case Feature::Name::NEGATIVE_IMPLS: - return Feature (Feature::Name::NEGATIVE_IMPLS, Feature::State::ACTIVE, - "negative_impls", "1.0.0", 68318, tl::nullopt, ""); + return Feature (f, Feature::State::ACTIVE, "negative_impls", "1.0.0", + 68318); case Feature::Name::BOX_SYNTAX: - return Feature (Feature::Name::BOX_SYNTAX, Feature::State::ACTIVE, - "box_syntax", "1.0.0", 49733, tl::nullopt, ""); + return Feature (f, Feature::State::ACTIVE, "box_syntax", "1.0.0", 49733); case Feature::Name::DROPCK_EYEPATCH: - return Feature (Feature::Name::DROPCK_EYEPATCH, Feature::State::ACTIVE, - "dropck_eyepatch", "1.10.0", 34761, tl::nullopt, ""); + return Feature (f, Feature::State::ACTIVE, "dropck_eyepatch", "1.10.0", + 34761); case Feature::Name::RAW_REF_OP: - return Feature (Feature::Name::RAW_REF_OP, Feature::State::ACTIVE, - "raw_ref_op", "1.41.0", 64490, tl::nullopt, ""); + return Feature (f, Feature::State::ACTIVE, "raw_ref_op", "1.41.0", 64490); case Feature::Name::EXCLUSIVE_RANGE_PATTERN: return Feature (Feature::Name::EXCLUSIVE_RANGE_PATTERN, Feature::State::ACTIVE, "exclusive_range_pattern", - "1.11.0", 37854, tl::nullopt, ""); + "1.11.0", 37854); + case Feature::Name::PRELUDE_IMPORT: + return Feature (f, Feature::State::ACTIVE, "prelude_import", "1.0.0"); + case Feature::Name::MIN_SPECIALIZATION: + return Feature (f, Feature::State::ACTIVE, "min_specialization", + "1.0.0" /* FIXME: What version here? */, 31844); + case Feature::Name::AUTO_TRAITS: + return Feature (f, Feature::State::ACTIVE, "optin_builtin_traits", + "1.0.0", 13231); default: rust_unreachable (); } @@ -79,6 +82,8 @@ const std::map<std::string, Feature::Name> Feature::name_hash_map = { {"dropck_eyepatch", Feature::Name::DROPCK_EYEPATCH}, {"raw_ref_op", Feature::Name::RAW_REF_OP}, {"exclusive_range_pattern", Feature::Name::EXCLUSIVE_RANGE_PATTERN}, + {"prelude_import", Feature::Name::PRELUDE_IMPORT}, + {"min_specialization", Feature::Name::MIN_SPECIALIZATION}, }; // namespace Rust tl::optional<Feature::Name> diff --git a/gcc/rust/checks/errors/rust-feature.h b/gcc/rust/checks/errors/rust-feature.h index 698aac2..e7cb0af 100644 --- a/gcc/rust/checks/errors/rust-feature.h +++ b/gcc/rust/checks/errors/rust-feature.h @@ -19,7 +19,7 @@ #ifndef RUST_FEATURE_H #define RUST_FEATURE_H -#include "rust-session-manager.h" +#include "rust-edition.h" #include "optional.h" namespace Rust { @@ -50,22 +50,25 @@ public: DROPCK_EYEPATCH, RAW_REF_OP, EXCLUSIVE_RANGE_PATTERN, + PRELUDE_IMPORT, + MIN_SPECIALIZATION, }; const std::string &as_string () { return m_name_str; } Name name () { return m_name; } const std::string &description () { return m_description; } State state () { return m_state; } - unsigned issue () { return m_issue; } + tl::optional<unsigned> issue () { return m_issue; } static tl::optional<Name> as_name (const std::string &name); static Feature create (Name name); private: Feature (Name name, State state, const char *name_str, - const char *rustc_since, unsigned issue_number, - const tl::optional<CompileOptions::Edition> &edition, - const char *description) + const char *rustc_since, + tl::optional<unsigned> issue_number = tl::nullopt, + const tl::optional<Edition> &edition = tl::nullopt, + const char *description = "") : m_state (state), m_name (name), m_name_str (name_str), m_rustc_since (rustc_since), m_issue (issue_number), edition (edition), m_description (description) @@ -75,9 +78,9 @@ private: Name m_name; std::string m_name_str; std::string m_rustc_since; - unsigned m_issue; - tl::optional<CompileOptions::Edition> edition; - std::string m_description; + tl::optional<unsigned> m_issue; + tl::optional<Edition> edition; + std::string m_description; // TODO: Switch to optional? static const std::map<std::string, Name> name_hash_map; }; diff --git a/gcc/rust/checks/errors/rust-hir-pattern-analysis.cc b/gcc/rust/checks/errors/rust-hir-pattern-analysis.cc new file mode 100644 index 0000000..648bc07 --- /dev/null +++ b/gcc/rust/checks/errors/rust-hir-pattern-analysis.cc @@ -0,0 +1,1556 @@ +// Copyright (C) 2020-2024 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-system.h" +#include "rust-hir-pattern-analysis.h" +#include "rust-diagnostics.h" +#include "rust-hir-full-decls.h" +#include "rust-hir-path.h" +#include "rust-hir-pattern.h" +#include "rust-hir.h" +#include "rust-mapping-common.h" +#include "rust-system.h" +#include "rust-tyty.h" +#include "rust-immutable-name-resolution-context.h" + +// for flag_name_resolution_2_0 +#include "options.h" + +namespace Rust { +namespace Analysis { + +PatternChecker::PatternChecker () + : tyctx (*Resolver::TypeCheckContext::get ()), + resolver (*Resolver::Resolver::get ()), + mappings (Analysis::Mappings::get ()) +{} + +void +PatternChecker::go (HIR::Crate &crate) +{ + rust_debug ("started pattern check"); + for (auto &item : crate.get_items ()) + item->accept_vis (*this); + rust_debug ("finished pattern check"); +} + +void +PatternChecker::visit (Lifetime &) +{} + +void +PatternChecker::visit (LifetimeParam &) +{} + +void +PatternChecker::visit (PathInExpression &path) +{} + +void +PatternChecker::visit (TypePathSegment &) +{} + +void +PatternChecker::visit (TypePathSegmentGeneric &) +{} + +void +PatternChecker::visit (TypePathSegmentFunction &) +{} + +void +PatternChecker::visit (TypePath &) +{} + +void +PatternChecker::visit (QualifiedPathInExpression &) +{} + +void +PatternChecker::visit (QualifiedPathInType &) +{} + +void +PatternChecker::visit (LiteralExpr &) +{} + +void +PatternChecker::visit (BorrowExpr &expr) +{ + expr.get_expr ().accept_vis (*this); +} + +void +PatternChecker::visit (DereferenceExpr &expr) +{ + expr.get_expr ().accept_vis (*this); +} + +void +PatternChecker::visit (ErrorPropagationExpr &expr) +{ + expr.get_expr ().accept_vis (*this); +} + +void +PatternChecker::visit (NegationExpr &expr) +{ + expr.get_expr ().accept_vis (*this); +} + +void +PatternChecker::visit (ArithmeticOrLogicalExpr &expr) +{ + expr.get_lhs ().accept_vis (*this); + expr.get_rhs ().accept_vis (*this); +} + +void +PatternChecker::visit (ComparisonExpr &expr) +{ + expr.get_lhs ().accept_vis (*this); + expr.get_rhs ().accept_vis (*this); +} + +void +PatternChecker::visit (LazyBooleanExpr &expr) +{ + expr.get_lhs ().accept_vis (*this); + expr.get_rhs ().accept_vis (*this); +} + +void +PatternChecker::visit (TypeCastExpr &expr) +{ + expr.get_expr ().accept_vis (*this); +} + +void +PatternChecker::visit (AssignmentExpr &expr) +{ + expr.get_lhs ().accept_vis (*this); + expr.get_rhs ().accept_vis (*this); +} + +void +PatternChecker::visit (CompoundAssignmentExpr &expr) +{ + expr.get_lhs ().accept_vis (*this); + expr.get_rhs ().accept_vis (*this); +} + +void +PatternChecker::visit (GroupedExpr &expr) +{ + expr.get_expr_in_parens ().accept_vis (*this); +} + +void +PatternChecker::visit (ArrayElemsValues &elems) +{ + for (auto &elem : elems.get_values ()) + elem->accept_vis (*this); +} + +void +PatternChecker::visit (ArrayElemsCopied &elems) +{ + elems.get_elem_to_copy ().accept_vis (*this); +} + +void +PatternChecker::visit (ArrayExpr &expr) +{ + expr.get_internal_elements ().accept_vis (*this); +} + +void +PatternChecker::visit (ArrayIndexExpr &expr) +{ + expr.get_array_expr ().accept_vis (*this); + expr.get_index_expr ().accept_vis (*this); +} + +void +PatternChecker::visit (TupleExpr &expr) +{ + for (auto &elem : expr.get_tuple_elems ()) + elem->accept_vis (*this); +} + +void +PatternChecker::visit (TupleIndexExpr &expr) +{ + expr.get_tuple_expr ().accept_vis (*this); +} + +void +PatternChecker::visit (StructExprStruct &) +{} + +void +PatternChecker::visit (StructExprFieldIdentifier &) +{} + +void +PatternChecker::visit (StructExprFieldIdentifierValue &field) +{ + field.get_value ().accept_vis (*this); +} + +void +PatternChecker::visit (StructExprFieldIndexValue &field) +{ + field.get_value ().accept_vis (*this); +} + +void +PatternChecker::visit (StructExprStructFields &expr) +{ + for (auto &field : expr.get_fields ()) + field->accept_vis (*this); +} + +void +PatternChecker::visit (StructExprStructBase &) +{} + +void +PatternChecker::visit (CallExpr &expr) +{ + if (!expr.has_fnexpr ()) + return; + + NodeId ast_node_id = expr.get_fnexpr ().get_mappings ().get_nodeid (); + NodeId ref_node_id; + if (flag_name_resolution_2_0) + { + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); + + if (auto id = nr_ctx.lookup (ast_node_id)) + ref_node_id = *id; + else + return; + } + else if (!resolver.lookup_resolved_name (ast_node_id, &ref_node_id)) + return; + + if (auto definition_id = mappings.lookup_node_to_hir (ref_node_id)) + { + if (expr.has_params ()) + for (auto &arg : expr.get_arguments ()) + arg->accept_vis (*this); + } + else + { + rust_unreachable (); + } +} + +void +PatternChecker::visit (MethodCallExpr &expr) +{ + expr.get_receiver ().accept_vis (*this); + + for (auto &arg : expr.get_arguments ()) + arg->accept_vis (*this); +} + +void +PatternChecker::visit (FieldAccessExpr &expr) +{ + expr.get_receiver_expr ().accept_vis (*this); +} + +void +PatternChecker::visit (ClosureExpr &expr) +{ + expr.get_expr ().accept_vis (*this); +} + +void +PatternChecker::visit (BlockExpr &expr) +{ + for (auto &stmt : expr.get_statements ()) + stmt->accept_vis (*this); + + if (expr.has_expr ()) + expr.get_final_expr ().accept_vis (*this); +} + +void +PatternChecker::visit (ContinueExpr &) +{} + +void +PatternChecker::visit (BreakExpr &expr) +{ + if (expr.has_break_expr ()) + expr.get_expr ().accept_vis (*this); +} + +void +PatternChecker::visit (RangeFromToExpr &expr) +{ + expr.get_from_expr ().accept_vis (*this); + expr.get_to_expr ().accept_vis (*this); +} + +void +PatternChecker::visit (RangeFromExpr &expr) +{ + expr.get_from_expr ().accept_vis (*this); +} + +void +PatternChecker::visit (RangeToExpr &expr) +{ + expr.get_to_expr ().accept_vis (*this); +} + +void +PatternChecker::visit (RangeFullExpr &) +{} + +void +PatternChecker::visit (RangeFromToInclExpr &expr) +{ + expr.get_from_expr ().accept_vis (*this); + expr.get_to_expr ().accept_vis (*this); +} + +void +PatternChecker::visit (RangeToInclExpr &expr) +{ + expr.get_to_expr ().accept_vis (*this); +} + +void +PatternChecker::visit (ReturnExpr &expr) +{ + if (expr.has_return_expr ()) + expr.get_expr ().accept_vis (*this); +} + +void +PatternChecker::visit (UnsafeBlockExpr &expr) +{ + expr.get_block_expr ().accept_vis (*this); +} + +void +PatternChecker::visit (LoopExpr &expr) +{ + expr.get_loop_block ().accept_vis (*this); +} + +void +PatternChecker::visit (WhileLoopExpr &expr) +{ + expr.get_predicate_expr ().accept_vis (*this); + expr.get_loop_block ().accept_vis (*this); +} + +void +PatternChecker::visit (WhileLetLoopExpr &expr) +{ + expr.get_cond ().accept_vis (*this); + expr.get_loop_block ().accept_vis (*this); +} + +void +PatternChecker::visit (IfExpr &expr) +{ + expr.get_if_condition ().accept_vis (*this); + expr.get_if_block ().accept_vis (*this); +} + +void +PatternChecker::visit (IfExprConseqElse &expr) +{ + expr.get_if_condition ().accept_vis (*this); + expr.get_if_block ().accept_vis (*this); + expr.get_else_block ().accept_vis (*this); +} + +void +PatternChecker::visit (MatchExpr &expr) +{ + expr.get_scrutinee_expr ().accept_vis (*this); + + for (auto &match_arm : expr.get_match_cases ()) + match_arm.get_expr ().accept_vis (*this); + + // match expressions are only an entrypoint + TyTy::BaseType *scrutinee_ty; + bool ok = tyctx.lookup_type ( + expr.get_scrutinee_expr ().get_mappings ().get_hirid (), &scrutinee_ty); + rust_assert (ok); + + check_match_usefulness (&tyctx, scrutinee_ty, expr); +} + +void +PatternChecker::visit (AwaitExpr &) +{ + // TODO: Visit expression +} + +void +PatternChecker::visit (AsyncBlockExpr &) +{ + // TODO: Visit block expression +} + +void +PatternChecker::visit (InlineAsm &expr) +{} + +void +PatternChecker::visit (LlvmInlineAsm &expr) +{} + +void +PatternChecker::visit (TypeParam &) +{} + +void +PatternChecker::visit (ConstGenericParam &) +{} + +void +PatternChecker::visit (LifetimeWhereClauseItem &) +{} + +void +PatternChecker::visit (TypeBoundWhereClauseItem &) +{} + +void +PatternChecker::visit (Module &module) +{ + for (auto &item : module.get_items ()) + item->accept_vis (*this); +} + +void +PatternChecker::visit (ExternCrate &) +{} + +void +PatternChecker::visit (UseTreeGlob &) +{} + +void +PatternChecker::visit (UseTreeList &) +{} + +void +PatternChecker::visit (UseTreeRebind &) +{} + +void +PatternChecker::visit (UseDeclaration &) +{} + +void +PatternChecker::visit (Function &function) +{ + function.get_definition ().accept_vis (*this); +} + +void +PatternChecker::visit (TypeAlias &) +{} + +void +PatternChecker::visit (StructStruct &) +{} + +void +PatternChecker::visit (TupleStruct &) +{} + +void +PatternChecker::visit (EnumItem &) +{} + +void +PatternChecker::visit (EnumItemTuple &) +{} + +void +PatternChecker::visit (EnumItemStruct &) +{} + +void +PatternChecker::visit (EnumItemDiscriminant &) +{} + +void +PatternChecker::visit (Enum &) +{} + +void +PatternChecker::visit (Union &) +{} + +void +PatternChecker::visit (ConstantItem &const_item) +{ + const_item.get_expr ().accept_vis (*this); +} + +void +PatternChecker::visit (StaticItem &static_item) +{ + static_item.get_expr ().accept_vis (*this); +} + +void +PatternChecker::visit (TraitItemFunc &item) +{ + if (item.has_definition ()) + item.get_block_expr ().accept_vis (*this); +} + +void +PatternChecker::visit (TraitItemConst &item) +{ + if (item.has_expr ()) + item.get_expr ().accept_vis (*this); +} + +void +PatternChecker::visit (TraitItemType &) +{} + +void +PatternChecker::visit (Trait &trait) +{ + for (auto &item : trait.get_trait_items ()) + item->accept_vis (*this); +} + +void +PatternChecker::visit (ImplBlock &impl) +{ + for (auto &item : impl.get_impl_items ()) + item->accept_vis (*this); +} + +void +PatternChecker::visit (ExternalStaticItem &) +{} + +void +PatternChecker::visit (ExternalFunctionItem &) +{} + +void +PatternChecker::visit (ExternalTypeItem &) +{} + +void +PatternChecker::visit (ExternBlock &block) +{ + // FIXME: Do we need to do this? + for (auto &item : block.get_extern_items ()) + item->accept_vis (*this); +} + +void +PatternChecker::visit (LiteralPattern &) +{} + +void +PatternChecker::visit (IdentifierPattern &) +{} + +void +PatternChecker::visit (WildcardPattern &) +{} + +void +PatternChecker::visit (RangePatternBoundLiteral &) +{} + +void +PatternChecker::visit (RangePatternBoundPath &) +{} + +void +PatternChecker::visit (RangePatternBoundQualPath &) +{} + +void +PatternChecker::visit (RangePattern &) +{} + +void +PatternChecker::visit (ReferencePattern &) +{} + +void +PatternChecker::visit (StructPatternFieldTuplePat &) +{} + +void +PatternChecker::visit (StructPatternFieldIdentPat &) +{} + +void +PatternChecker::visit (StructPatternFieldIdent &) +{} + +void +PatternChecker::visit (StructPattern &) +{} + +void +PatternChecker::visit (TupleStructItemsNoRange &) +{} + +void +PatternChecker::visit (TupleStructItemsRange &) +{} + +void +PatternChecker::visit (TupleStructPattern &) +{} + +void +PatternChecker::visit (TuplePatternItemsMultiple &) +{} + +void +PatternChecker::visit (TuplePatternItemsRanged &) +{} + +void +PatternChecker::visit (TuplePattern &) +{} + +void +PatternChecker::visit (SlicePattern &) +{} + +void +PatternChecker::visit (AltPattern &) +{} + +void +PatternChecker::visit (EmptyStmt &) +{} + +void +PatternChecker::visit (LetStmt &stmt) +{ + if (stmt.has_init_expr ()) + stmt.get_init_expr ().accept_vis (*this); +} + +void +PatternChecker::visit (ExprStmt &stmt) +{ + stmt.get_expr ().accept_vis (*this); +} + +void +PatternChecker::visit (TraitBound &) +{} + +void +PatternChecker::visit (ImplTraitType &) +{} + +void +PatternChecker::visit (TraitObjectType &) +{} + +void +PatternChecker::visit (ParenthesisedType &) +{} + +void +PatternChecker::visit (TupleType &) +{} + +void +PatternChecker::visit (NeverType &) +{} + +void +PatternChecker::visit (RawPointerType &) +{} + +void +PatternChecker::visit (ReferenceType &) +{} + +void +PatternChecker::visit (ArrayType &) +{} + +void +PatternChecker::visit (SliceType &) +{} + +void +PatternChecker::visit (InferredType &) +{} + +void +PatternChecker::visit (BareFunctionType &) +{} + +bool +Constructor::is_covered_by (const Constructor &o) const +{ + if (o.kind == ConstructorKind::WILDCARD) + return true; + + switch (kind) + { + case ConstructorKind::VARIANT: { + rust_assert (kind == ConstructorKind::VARIANT); + return variant_idx == o.variant_idx; + } + break; + case ConstructorKind::INT_RANGE: { + rust_assert (kind == ConstructorKind::INT_RANGE); + return int_range.lo >= o.int_range.lo && int_range.hi <= o.int_range.hi; + } + break; + case ConstructorKind::WILDCARD: { + // TODO: wildcard is covered by a variant of enum with a single + // variant + return false; + } + break; + case ConstructorKind::STRUCT: { + // Struct pattern is always covered by a other struct constructor. + return true; + } + break; + // TODO: support references + case ConstructorKind::REFERENCE: + default: + rust_unreachable (); + } +} + +bool +Constructor::operator< (const Constructor &o) const +{ + if (kind != o.kind) + return kind < o.kind; + + switch (kind) + { + case ConstructorKind::VARIANT: + return variant_idx < o.variant_idx; + case ConstructorKind::INT_RANGE: + return int_range.lo < o.int_range.lo + || (int_range.lo == o.int_range.lo + && int_range.hi < o.int_range.hi); + case ConstructorKind::STRUCT: + case ConstructorKind::WILDCARD: + case ConstructorKind::REFERENCE: + return false; + default: + rust_unreachable (); + } +} + +std::string +Constructor::to_string () const +{ + switch (kind) + { + case ConstructorKind::STRUCT: + return "STRUCT"; + case ConstructorKind::VARIANT: + return "VARIANT(" + std::to_string (variant_idx) + ")"; + case ConstructorKind::INT_RANGE: + return "RANGE" + std::to_string (int_range.lo) + ".." + + std::to_string (int_range.hi); + case ConstructorKind::WILDCARD: + return "_"; + case ConstructorKind::REFERENCE: + return "REF"; + default: + rust_unreachable (); + } +} + +std::vector<DeconstructedPat> +DeconstructedPat::specialize (const Constructor &other_ctor, + int other_ctor_arity) const +{ + rust_assert (other_ctor.is_covered_by (ctor)); + if (ctor.is_wildcard ()) + return std::vector<DeconstructedPat> ( + other_ctor_arity, + DeconstructedPat (Constructor::make_wildcard (), locus)); + + return fields; +} + +std::string +DeconstructedPat::to_string () const +{ + std::string s = ctor.to_string () + "["; + for (auto &f : fields) + s += f.to_string () + ", "; + + s += "](arity=" + std::to_string (arity) + ")"; + return s; +} + +bool +PatOrWild::is_covered_by (const Constructor &c) const +{ + if (pat.has_value ()) + return pat.value ().get_ctor ().is_covered_by (c); + else + return true; +} + +std::vector<PatOrWild> +PatOrWild::specialize (const Constructor &other_ctor, + int other_ctor_arity) const +{ + if (pat.has_value ()) + { + auto v = pat.value ().specialize (other_ctor, other_ctor_arity); + std::vector<PatOrWild> ret; + for (auto &pat : v) + ret.push_back (PatOrWild::make_pattern (pat)); + + return ret; + } + else + { + return std::vector<PatOrWild> (other_ctor_arity, + PatOrWild::make_wildcard ()); + } +} + +std::string +PatOrWild::to_string () const +{ + if (pat.has_value ()) + return pat.value ().to_string (); + else + return "Wild"; +} + +void +PatStack::pop_head_constructor (const Constructor &other_ctor, + int other_ctor_arity) +{ + rust_assert (!pats.empty ()); + rust_assert (other_ctor.is_covered_by (head ().ctor ())); + + PatOrWild &hd = head (); + auto v = hd.specialize (other_ctor, other_ctor_arity); + { + std::string s = "["; + for (auto &pat : v) + s += pat.to_string () + ", "; + s += "]"; + + rust_debug ("specialize %s with %s to %s", hd.to_string ().c_str (), + other_ctor.to_string ().c_str (), s.c_str ()); + } + pop_head (); + for (auto &pat : v) + pats.push_back (pat); +} + +std::string +MatrixRow::to_string () const +{ + std::string s; + for (const PatOrWild &pat : pats.get_subpatterns ()) + s += pat.to_string () + ", "; + return s; +} + +std::vector<PlaceInfo> +PlaceInfo::specialize (const Constructor &c) const +{ + switch (c.get_kind ()) + { + case Constructor::ConstructorKind::WILDCARD: + case Constructor::ConstructorKind::INT_RANGE: { + return {}; + } + break; + case Constructor::ConstructorKind::STRUCT: + case Constructor::ConstructorKind::VARIANT: { + rust_assert (ty->get_kind () == TyTy::TypeKind::ADT); + TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (ty); + switch (adt->get_adt_kind ()) + { + case TyTy::ADTType::ADTKind::ENUM: + case TyTy::ADTType::ADTKind::STRUCT_STRUCT: + case TyTy::ADTType::ADTKind::TUPLE_STRUCT: { + TyTy::VariantDef *variant + = adt->get_variants ().at (c.get_variant_index ()); + if (variant->get_variant_type () + == TyTy::VariantDef::VariantType::NUM) + return {}; + + std::vector<PlaceInfo> new_place_infos; + for (auto &field : variant->get_fields ()) + new_place_infos.push_back (field->get_field_type ()); + + return new_place_infos; + } + break; + case TyTy::ADTType::ADTKind::UNION: { + // TODO: support unions + rust_unreachable (); + } + } + } + break; + default: { + rust_unreachable (); + } + break; + } + + rust_unreachable (); +} + +Matrix +Matrix::specialize (const Constructor &ctor) const +{ + auto subfields_place_info = place_infos.at (0).specialize (ctor); + + std::vector<MatrixRow> new_rows; + for (const MatrixRow &row : rows) + { + PatStack pats = row.get_pats_clone (); + const PatOrWild &hd = pats.head (); + if (ctor.is_covered_by (hd.ctor ())) + { + pats.pop_head_constructor (ctor, subfields_place_info.size ()); + new_rows.push_back (MatrixRow (pats, row.is_under_guard ())); + } + } + + if (place_infos.empty ()) + return Matrix (new_rows, {}); + + // push subfields of the first fields after specialization + std::vector<PlaceInfo> new_place_infos = subfields_place_info; + // add place infos for the rest of the fields + for (size_t i = 1; i < place_infos.size (); i++) + new_place_infos.push_back (place_infos.at (i)); + + return Matrix (new_rows, new_place_infos); +} + +std::string +Matrix::to_string () const +{ + std::string s = "[\n"; + for (const MatrixRow &row : rows) + s += "row: " + row.to_string () + "\n"; + + s += "](place_infos=["; + for (const PlaceInfo &place_info : place_infos) + s += place_info.get_type ()->as_string () + ", "; + + s += "])"; + return s; +} + +std::string +WitnessPat::to_string () const +{ + switch (ctor.get_kind ()) + { + case Constructor::ConstructorKind::STRUCT: { + TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (ty); + TyTy::VariantDef *variant + = adt->get_variants ().at (ctor.get_variant_index ()); + std::string buf; + buf += adt->get_identifier (); + + buf += " {"; + if (!fields.empty ()) + buf += " "; + + for (size_t i = 0; i < fields.size (); i++) + { + buf += variant->get_fields ().at (i)->get_name () + ": "; + buf += fields.at (i).to_string (); + if (i < fields.size () - 1) + buf += ", "; + } + if (!fields.empty ()) + buf += " "; + + buf += "}"; + return buf; + } + break; + case Constructor::ConstructorKind::VARIANT: { + std::string buf; + TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (ty); + buf += adt->get_identifier (); + TyTy::VariantDef *variant + = adt->get_variants ().at (ctor.get_variant_index ()); + buf += "::" + variant->get_identifier (); + + switch (variant->get_variant_type ()) + { + case TyTy::VariantDef::VariantType::NUM: { + return buf; + } + break; + case TyTy::VariantDef::VariantType::TUPLE: { + buf += "("; + for (size_t i = 0; i < fields.size (); i++) + { + buf += fields.at (i).to_string (); + if (i < fields.size () - 1) + buf += ", "; + } + buf += ")"; + return buf; + } + break; + case TyTy::VariantDef::VariantType::STRUCT: { + buf += " {"; + if (!fields.empty ()) + buf += " "; + + for (size_t i = 0; i < fields.size (); i++) + { + buf += variant->get_fields ().at (i)->get_name () + ": "; + buf += fields.at (i).to_string (); + if (i < fields.size () - 1) + buf += ", "; + } + + if (!fields.empty ()) + buf += " "; + + buf += "}"; + } + break; + default: { + rust_unreachable (); + } + break; + } + return buf; + } + break; + case Constructor::ConstructorKind::INT_RANGE: { + // TODO: implement + rust_unreachable (); + } + break; + case Constructor::ConstructorKind::WILDCARD: { + return "_"; + } + break; + case Constructor::ConstructorKind::REFERENCE: { + // TODO: implement + rust_unreachable (); + } + break; + default: { + rust_unreachable (); + } + break; + } + rust_unreachable (); +} + +void +WitnessMatrix::apply_constructor (const Constructor &ctor, + const std::set<Constructor> &missings, + TyTy::BaseType *ty) +{ + int arity = 0; + // TODO: only support struct and variant ctor for now. + switch (ctor.get_kind ()) + { + case Constructor::ConstructorKind::WILDCARD: { + arity = 0; + } + break; + case Constructor::ConstructorKind::STRUCT: + case Constructor::ConstructorKind::VARIANT: { + if (ty->get_kind () == TyTy::TypeKind::ADT) + { + TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (ty); + TyTy::VariantDef *variant + = adt->get_variants ().at (ctor.get_variant_index ()); + if (variant->get_variant_type () == TyTy::VariantDef::NUM) + arity = 0; + else + arity = variant->get_fields ().size (); + } + } + break; + default: { + rust_unreachable (); + } + } + + std::string buf; + for (auto &stack : patstacks) + { + buf += "["; + for (auto &pat : stack) + buf += pat.to_string () + ", "; + + buf += "]\n"; + } + rust_debug ("witness pats:\n%s", buf.c_str ()); + + for (auto &stack : patstacks) + { + std::vector<WitnessPat> subfield; + for (int i = 0; i < arity; i++) + { + if (stack.empty ()) + subfield.push_back (WitnessPat::make_wildcard (ty)); + else + { + subfield.push_back (stack.back ()); + stack.pop_back (); + } + } + + stack.push_back (WitnessPat (ctor, subfield, ty)); + } +} + +void +WitnessMatrix::extend (const WitnessMatrix &other) +{ + patstacks.insert (patstacks.end (), other.patstacks.begin (), + other.patstacks.end ()); +} + +// forward declarations +static DeconstructedPat +lower_pattern (Resolver::TypeCheckContext *ctx, HIR::Pattern &pattern, + TyTy::BaseType *scrutinee_ty); + +static DeconstructedPat +lower_tuple_pattern (Resolver::TypeCheckContext *ctx, + HIR::TupleStructPattern &pattern, + TyTy::VariantDef *variant, Constructor &ctor) +{ + int arity = variant->get_fields ().size (); + HIR::TupleStructItems &elems = pattern.get_items (); + + std::vector<DeconstructedPat> fields; + switch (elems.get_item_type ()) + { + case HIR::TupleStructItems::ItemType::MULTIPLE: { + HIR::TupleStructItemsNoRange &multiple + = static_cast<HIR::TupleStructItemsNoRange &> (elems); + + rust_assert (variant->get_fields ().size () + == multiple.get_patterns ().size ()); + + for (size_t i = 0; i < multiple.get_patterns ().size (); i++) + { + fields.push_back ( + lower_pattern (ctx, *multiple.get_patterns ().at (i), + variant->get_fields ().at (i)->get_field_type ())); + } + return DeconstructedPat (ctor, arity, fields, pattern.get_locus ()); + } + break; + case HIR::TupleStructItems::ItemType::RANGED: { + // TODO: ranged tuple struct items + rust_unreachable (); + } + break; + default: { + rust_unreachable (); + } + } +} + +static DeconstructedPat +lower_struct_pattern (Resolver::TypeCheckContext *ctx, + HIR::StructPattern &pattern, TyTy::VariantDef *variant, + Constructor ctor) +{ + int arity = variant->get_fields ().size (); + + // Initialize all field patterns to wildcard. + std::vector<DeconstructedPat> fields + = std::vector<DeconstructedPat> (arity, DeconstructedPat::make_wildcard ( + pattern.get_locus ())); + + std::map<std::string, int> field_map; + for (int i = 0; i < arity; i++) + { + auto &f = variant->get_fields ().at (i); + field_map[f->get_name ()] = i; + } + + // Fill in the fields with the present patterns. + HIR::StructPatternElements elems = pattern.get_struct_pattern_elems (); + for (auto &elem : elems.get_struct_pattern_fields ()) + { + switch (elem->get_item_type ()) + { + case HIR::StructPatternField::ItemType::IDENT: { + HIR::StructPatternFieldIdent *ident + = static_cast<HIR::StructPatternFieldIdent *> (elem.get ()); + int field_idx + = field_map.at (ident->get_identifier ().as_string ()); + fields.at (field_idx) + = DeconstructedPat::make_wildcard (pattern.get_locus ()); + } + break; + case HIR::StructPatternField::ItemType::IDENT_PAT: { + HIR::StructPatternFieldIdentPat *ident_pat + = static_cast<HIR::StructPatternFieldIdentPat *> (elem.get ()); + int field_idx + = field_map.at (ident_pat->get_identifier ().as_string ()); + fields.at (field_idx) = lower_pattern ( + ctx, ident_pat->get_pattern (), + variant->get_fields ().at (field_idx)->get_field_type ()); + } + break; + case HIR::StructPatternField::ItemType::TUPLE_PAT: { + // TODO: tuple: pat + rust_unreachable (); + } + break; + default: { + rust_unreachable (); + } + } + } + + return DeconstructedPat{ctor, arity, fields, pattern.get_locus ()}; +}; + +static DeconstructedPat +lower_pattern (Resolver::TypeCheckContext *ctx, HIR::Pattern &pattern, + TyTy::BaseType *scrutinee_ty) +{ + HIR::Pattern::PatternType pat_type = pattern.get_pattern_type (); + switch (pat_type) + { + case HIR::Pattern::PatternType::WILDCARD: + case HIR::Pattern::PatternType::IDENTIFIER: { + return DeconstructedPat::make_wildcard (pattern.get_locus ()); + } + break; + case HIR::Pattern::PatternType::PATH: { + // TODO: support constants, associated constants, enum variants and + // structs + // https://doc.rust-lang.org/reference/patterns.html#path-patterns + // unimplemented. Treat this pattern as wildcard for now. + return DeconstructedPat::make_wildcard (pattern.get_locus ()); + } + break; + case HIR::Pattern::PatternType::REFERENCE: { + // TODO: unimplemented. Treat this pattern as wildcard for now. + return DeconstructedPat::make_wildcard (pattern.get_locus ()); + } + break; + case HIR::Pattern::PatternType::STRUCT: + case HIR::Pattern::PatternType::TUPLE_STRUCT: { + HirId path_id = UNKNOWN_HIRID; + if (pat_type == HIR::Pattern::PatternType::STRUCT) + { + HIR::StructPattern &struct_pattern + = static_cast<HIR::StructPattern &> (pattern); + path_id = struct_pattern.get_path ().get_mappings ().get_hirid (); + } + else + { + HIR::TupleStructPattern &tuple_pattern + = static_cast<HIR::TupleStructPattern &> (pattern); + path_id = tuple_pattern.get_path ().get_mappings ().get_hirid (); + } + + rust_assert (scrutinee_ty->get_kind () == TyTy::TypeKind::ADT); + TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (scrutinee_ty); + + Constructor ctor = Constructor::make_struct (); + TyTy::VariantDef *variant; + if (adt->is_struct_struct () || adt->is_tuple_struct ()) + variant = adt->get_variants ().at (0); + else if (adt->is_enum ()) + { + HirId variant_id = UNKNOWN_HIRID; + bool ok = ctx->lookup_variant_definition (path_id, &variant_id); + rust_assert (ok); + + int variant_idx; + ok = adt->lookup_variant_by_id (variant_id, &variant, &variant_idx); + rust_assert (ok); + + ctor = Constructor::make_variant (variant_idx); + } + else + { + rust_unreachable (); + } + rust_assert (variant->get_variant_type () + == TyTy::VariantDef::VariantType::TUPLE + || variant->get_variant_type () + == TyTy::VariantDef::VariantType::STRUCT); + + if (pat_type == HIR::Pattern::PatternType::STRUCT) + { + HIR::StructPattern &struct_pattern + = static_cast<HIR::StructPattern &> (pattern); + return lower_struct_pattern (ctx, struct_pattern, variant, ctor); + } + else + { + HIR::TupleStructPattern &tuple_pattern + = static_cast<HIR::TupleStructPattern &> (pattern); + return lower_tuple_pattern (ctx, tuple_pattern, variant, ctor); + } + } + break; + case HIR::Pattern::PatternType::TUPLE: { + // TODO: unimplemented. Treat this pattern as wildcard for now. + return DeconstructedPat::make_wildcard (pattern.get_locus ()); + } + break; + case HIR::Pattern::PatternType::SLICE: { + // TODO: unimplemented. Treat this pattern as wildcard for now. + return DeconstructedPat::make_wildcard (pattern.get_locus ()); + } + break; + case HIR::Pattern::PatternType::ALT: { + // TODO: unimplemented. Treat this pattern as wildcard for now. + return DeconstructedPat::make_wildcard (pattern.get_locus ()); + } + break; + case HIR::Pattern::PatternType::LITERAL: { + // TODO: unimplemented. Treat this pattern as wildcard for now. + return DeconstructedPat::make_wildcard (pattern.get_locus ()); + } + break; + case HIR::Pattern::PatternType::RANGE: { + // TODO: unimplemented. Treat this pattern as wildcard for now. + return DeconstructedPat::make_wildcard (pattern.get_locus ()); + } + break; + case HIR::Pattern::PatternType::GROUPED: { + // TODO: unimplemented. Treat this pattern as wildcard for now. + return DeconstructedPat::make_wildcard (pattern.get_locus ()); + } + break; + default: { + rust_unreachable (); + } + } +} + +static MatchArm +lower_arm (Resolver::TypeCheckContext *ctx, HIR::MatchCase &arm, + TyTy::BaseType *scrutinee_ty) +{ + rust_assert (arm.get_arm ().get_patterns ().size () > 0); + + DeconstructedPat pat + = lower_pattern (ctx, *arm.get_arm ().get_patterns ().at (0), scrutinee_ty); + return MatchArm (pat, arm.get_arm ().has_match_arm_guard ()); +} + +std::pair<std::set<Constructor>, std::set<Constructor>> +split_constructors (std::vector<Constructor> &ctors, PlaceInfo &place_info) +{ + bool all_wildcard = true; + for (auto &ctor : ctors) + { + if (!ctor.is_wildcard ()) + all_wildcard = false; + } + + // first pass for the case that all patterns are wildcard + if (all_wildcard) + return std::make_pair (std::set<Constructor> ( + {Constructor::make_wildcard ()}), + std::set<Constructor> ()); + + // TODO: only support enums and structs for now. + TyTy::BaseType *ty = place_info.get_type (); + rust_assert (ty->get_kind () == TyTy::TypeKind::ADT); + TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (ty); + rust_assert (adt->is_enum () || adt->is_struct_struct () + || adt->is_tuple_struct ()); + + std::set<Constructor> universe; + if (adt->is_enum ()) + { + for (size_t i = 0; i < adt->get_variants ().size (); i++) + universe.insert (Constructor::make_variant (i)); + } + else if (adt->is_struct_struct () || adt->is_tuple_struct ()) + { + universe.insert (Constructor::make_struct ()); + } + + std::set<Constructor> present; + for (auto &ctor : ctors) + { + if (ctor.is_wildcard ()) + return std::make_pair (universe, std::set<Constructor> ()); + else + present.insert (ctor); + } + + std::set<Constructor> missing; + std::set_difference (universe.begin (), universe.end (), present.begin (), + present.end (), std::inserter (missing, missing.end ())); + return std::make_pair (universe, missing); +} + +// The core of the algorithm. It computes the usefulness and exhaustiveness of a +// given matrix recursively. +// TODO: calculate usefulness +static WitnessMatrix +compute_exhaustiveness_and_usefulness (Resolver::TypeCheckContext *ctx, + Matrix &matrix) +{ + rust_debug ("call compute_exhaustiveness_and_usefulness"); + rust_debug ("matrix: %s", matrix.to_string ().c_str ()); + + if (matrix.get_rows ().empty ()) + { + // no rows left. This means a non-exhaustive pattern. + rust_debug ("non-exhaustive subpattern found"); + return WitnessMatrix::make_unit (); + } + + // Base case: there are no columns in matrix. + if (matrix.get_place_infos ().empty ()) + return WitnessMatrix::make_empty (); + + std::vector<Constructor> heads; + for (auto head : matrix.heads ()) + heads.push_back (head.ctor ()); + + // TODO: not sure missing ctors need to be calculated + auto ctors_and_missings + = split_constructors (heads, matrix.get_place_infos ().at (0)); + std::set<Constructor> ctors = ctors_and_missings.first; + std::set<Constructor> missings = ctors_and_missings.second; + + WitnessMatrix ret = WitnessMatrix::make_empty (); + for (auto &ctor : ctors) + { + rust_debug ("specialize with %s", ctor.to_string ().c_str ()); + // TODO: Instead of creating new matrix, we can change the original matrix + // and use it for sub-pattern matching. It will significantly reduce + // memory usage. + Matrix spec_matrix = matrix.specialize (ctor); + + WitnessMatrix witness + = compute_exhaustiveness_and_usefulness (ctx, spec_matrix); + + TyTy::BaseType *ty = matrix.get_place_infos ().at (0).get_type (); + witness.apply_constructor (ctor, missings, ty); + ret.extend (witness); + } + + return ret; +} + +static void +emit_exhaustiveness_error (Resolver::TypeCheckContext *ctx, + HIR::MatchExpr &expr, WitnessMatrix &witness) +{ + TyTy::BaseType *scrutinee_ty; + bool ok + = ctx->lookup_type (expr.get_scrutinee_expr ().get_mappings ().get_hirid (), + &scrutinee_ty); + rust_assert (ok); + + if (!witness.empty ()) + { + std::stringstream buf; + for (size_t i = 0; i < witness.get_stacks ().size (); i++) + { + auto &stack = witness.get_stacks ().at (i); + WitnessPat w = WitnessPat::make_wildcard (scrutinee_ty); + if (!stack.empty ()) + w = stack.at (0); + + rust_debug ("Witness[%d]: %s", (int) i, w.to_string ().c_str ()); + buf << "'" << w.to_string () << "'"; + if (i != witness.get_stacks ().size () - 1) + buf << " and "; + } + rust_error_at (expr.get_scrutinee_expr ().get_locus (), + "non-exhaustive patterns: %s not covered", + buf.str ().c_str ()); + } + else + { + rust_debug ("no witness found"); + } +} + +// Entry point for computing match usefulness and check exhaustiveness +void +check_match_usefulness (Resolver::TypeCheckContext *ctx, + TyTy::BaseType *scrutinee_ty, HIR::MatchExpr &expr) +{ + if (!expr.has_match_arms ()) + return; + + // Lower the arms to a more convenient representation. + std::vector<MatrixRow> rows; + for (auto &arm : expr.get_match_cases ()) + { + PatStack pats; + MatchArm lowered = lower_arm (ctx, arm, scrutinee_ty); + PatOrWild pat = PatOrWild::make_pattern (lowered.get_pat ()); + pats.push (pat); + rows.push_back (MatrixRow (pats, lowered.has_guard ())); + } + + std::vector<PlaceInfo> place_infos = {{PlaceInfo (scrutinee_ty)}}; + Matrix matrix{rows, place_infos}; + + WitnessMatrix witness = compute_exhaustiveness_and_usefulness (ctx, matrix); + + emit_exhaustiveness_error (ctx, expr, witness); +} + +} // namespace Analysis +} // namespace Rust diff --git a/gcc/rust/checks/errors/rust-hir-pattern-analysis.h b/gcc/rust/checks/errors/rust-hir-pattern-analysis.h new file mode 100644 index 0000000..6d60ced --- /dev/null +++ b/gcc/rust/checks/errors/rust-hir-pattern-analysis.h @@ -0,0 +1,524 @@ +// Copyright (C) 2020-2024 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_HIR_PATTERN_ANALYSIS_H +#define RUST_HIR_PATTERN_ANALYSIS_H + +#include "rust-system.h" +#include "rust-hir-expr.h" +#include "rust-hir-type-check.h" +#include "rust-system.h" +#include "rust-tyty.h" +#include "optional.h" +#include "rust-hir-visitor.h" +#include "rust-name-resolver.h" + +namespace Rust { +namespace Analysis { + +using namespace HIR; + +void +check_match_usefulness (Resolver::TypeCheckContext *ctx, + TyTy::BaseType *scrutinee_ty, HIR::MatchExpr &expr); + +class PatternChecker : public HIR::HIRFullVisitor +{ +public: + PatternChecker (); + + void go (HIR::Crate &crate); + +private: + Resolver::TypeCheckContext &tyctx; + Resolver::Resolver &resolver; + Analysis::Mappings &mappings; + + virtual void visit (Lifetime &lifetime) override; + virtual void visit (LifetimeParam &lifetime_param) override; + virtual void visit (PathInExpression &path) override; + virtual void visit (TypePathSegment &segment) override; + virtual void visit (TypePathSegmentGeneric &segment) override; + virtual void visit (TypePathSegmentFunction &segment) override; + virtual void visit (TypePath &path) override; + virtual void visit (QualifiedPathInExpression &path) override; + virtual void visit (QualifiedPathInType &path) override; + virtual void visit (LiteralExpr &expr) override; + virtual void visit (BorrowExpr &expr) override; + virtual void visit (DereferenceExpr &expr) override; + virtual void visit (ErrorPropagationExpr &expr) override; + virtual void visit (NegationExpr &expr) override; + virtual void visit (ArithmeticOrLogicalExpr &expr) override; + virtual void visit (ComparisonExpr &expr) override; + virtual void visit (LazyBooleanExpr &expr) override; + virtual void visit (TypeCastExpr &expr) override; + virtual void visit (AssignmentExpr &expr) override; + virtual void visit (CompoundAssignmentExpr &expr) override; + virtual void visit (GroupedExpr &expr) override; + virtual void visit (ArrayElemsValues &elems) override; + virtual void visit (ArrayElemsCopied &elems) override; + virtual void visit (ArrayExpr &expr) override; + virtual void visit (ArrayIndexExpr &expr) override; + virtual void visit (TupleExpr &expr) override; + virtual void visit (TupleIndexExpr &expr) override; + virtual void visit (StructExprStruct &expr) override; + virtual void visit (StructExprFieldIdentifier &field) override; + virtual void visit (StructExprFieldIdentifierValue &field) override; + virtual void visit (StructExprFieldIndexValue &field) override; + virtual void visit (StructExprStructFields &expr) override; + virtual void visit (StructExprStructBase &expr) override; + virtual void visit (CallExpr &expr) override; + virtual void visit (MethodCallExpr &expr) override; + virtual void visit (FieldAccessExpr &expr) override; + virtual void visit (BlockExpr &expr) override; + virtual void visit (ClosureExpr &expr) override; + virtual void visit (ContinueExpr &expr) override; + virtual void visit (BreakExpr &expr) override; + virtual void visit (RangeFromToExpr &expr) override; + virtual void visit (RangeFromExpr &expr) override; + virtual void visit (RangeToExpr &expr) override; + virtual void visit (RangeFullExpr &expr) override; + virtual void visit (RangeFromToInclExpr &expr) override; + virtual void visit (RangeToInclExpr &expr) override; + virtual void visit (ReturnExpr &expr) override; + virtual void visit (UnsafeBlockExpr &expr) override; + virtual void visit (LoopExpr &expr) override; + virtual void visit (WhileLoopExpr &expr) override; + virtual void visit (WhileLetLoopExpr &expr) override; + virtual void visit (IfExpr &expr) override; + virtual void visit (IfExprConseqElse &expr) override; + virtual void visit (HIR::MatchExpr &expr) override; + virtual void visit (AwaitExpr &expr) override; + virtual void visit (AsyncBlockExpr &expr) override; + virtual void visit (InlineAsm &expr) override; + virtual void visit (LlvmInlineAsm &expr) override; + virtual void visit (TypeParam ¶m) override; + virtual void visit (ConstGenericParam ¶m) override; + virtual void visit (LifetimeWhereClauseItem &item) override; + virtual void visit (TypeBoundWhereClauseItem &item) override; + virtual void visit (Module &module) override; + virtual void visit (ExternCrate &crate) override; + virtual void visit (UseTreeGlob &use_tree) override; + virtual void visit (UseTreeList &use_tree) override; + virtual void visit (UseTreeRebind &use_tree) override; + virtual void visit (UseDeclaration &use_decl) override; + virtual void visit (Function &function) override; + virtual void visit (TypeAlias &type_alias) override; + virtual void visit (StructStruct &struct_item) override; + virtual void visit (TupleStruct &tuple_struct) override; + virtual void visit (EnumItem &item) override; + virtual void visit (EnumItemTuple &item) override; + virtual void visit (EnumItemStruct &item) override; + virtual void visit (EnumItemDiscriminant &item) override; + virtual void visit (Enum &enum_item) override; + virtual void visit (Union &union_item) override; + virtual void visit (ConstantItem &const_item) override; + virtual void visit (StaticItem &static_item) override; + virtual void visit (TraitItemFunc &item) override; + virtual void visit (TraitItemConst &item) override; + virtual void visit (TraitItemType &item) override; + virtual void visit (Trait &trait) override; + virtual void visit (ImplBlock &impl) override; + virtual void visit (ExternalStaticItem &item) override; + virtual void visit (ExternalFunctionItem &item) override; + virtual void visit (ExternalTypeItem &item) override; + virtual void visit (ExternBlock &block) override; + virtual void visit (LiteralPattern &pattern) override; + virtual void visit (IdentifierPattern &pattern) override; + virtual void visit (WildcardPattern &pattern) override; + virtual void visit (RangePatternBoundLiteral &bound) override; + virtual void visit (RangePatternBoundPath &bound) override; + virtual void visit (RangePatternBoundQualPath &bound) override; + virtual void visit (RangePattern &pattern) override; + virtual void visit (ReferencePattern &pattern) override; + virtual void visit (StructPatternFieldTuplePat &field) override; + virtual void visit (StructPatternFieldIdentPat &field) override; + virtual void visit (StructPatternFieldIdent &field) override; + virtual void visit (StructPattern &pattern) override; + virtual void visit (TupleStructItemsNoRange &tuple_items) override; + virtual void visit (TupleStructItemsRange &tuple_items) override; + virtual void visit (TupleStructPattern &pattern) override; + virtual void visit (TuplePatternItemsMultiple &tuple_items) override; + virtual void visit (TuplePatternItemsRanged &tuple_items) override; + virtual void visit (TuplePattern &pattern) override; + virtual void visit (SlicePattern &pattern) override; + virtual void visit (AltPattern &pattern) override; + virtual void visit (EmptyStmt &stmt) override; + virtual void visit (LetStmt &stmt) override; + virtual void visit (ExprStmt &stmt) override; + virtual void visit (TraitBound &bound) override; + virtual void visit (ImplTraitType &type) override; + virtual void visit (TraitObjectType &type) override; + virtual void visit (ParenthesisedType &type) override; + virtual void visit (TupleType &type) override; + virtual void visit (NeverType &type) override; + virtual void visit (RawPointerType &type) override; + virtual void visit (ReferenceType &type) override; + virtual void visit (ArrayType &type) override; + virtual void visit (SliceType &type) override; + virtual void visit (InferredType &type) override; + virtual void visit (BareFunctionType &type) override; +}; + +struct IntRange +{ + int64_t lo; + int64_t hi; +}; + +class Constructor +{ +public: + enum class ConstructorKind + { + // tuple or struct + STRUCT, + // enum variant + VARIANT, + // integers + INT_RANGE, + // user-provided wildcard + WILDCARD, + // references + REFERENCE, + }; + + static Constructor make_wildcard () + { + return Constructor (ConstructorKind::WILDCARD); + } + + static Constructor make_reference () + { + return Constructor (ConstructorKind::REFERENCE); + } + + static Constructor make_struct () + { + Constructor c (ConstructorKind::STRUCT); + c.variant_idx = 0; + return c; + } + + static Constructor make_variant (int variant_idx) + { + Constructor c (ConstructorKind::VARIANT); + c.variant_idx = variant_idx; + return c; + } + + ConstructorKind get_kind () const { return kind; } + + int get_variant_index () const + { + rust_assert (kind == ConstructorKind::VARIANT + || kind == ConstructorKind::STRUCT); + return variant_idx; + } + + bool is_covered_by (const Constructor &o) const; + + bool is_wildcard () const { return kind == ConstructorKind::WILDCARD; } + + // Requrired by std::set<T> + bool operator< (const Constructor &o) const; + + std::string to_string () const; + +private: + Constructor (ConstructorKind kind) : kind (kind), variant_idx (0) {} + ConstructorKind kind; + + union + { + // for enum variants, the variant index (always 0 for structs) + int variant_idx; + + // for integer ranges, the range + IntRange int_range; + }; +}; + +class DeconstructedPat +{ +public: + DeconstructedPat (Constructor ctor, int arity, + std::vector<DeconstructedPat> fields, location_t locus) + : ctor (ctor), arity (arity), fields (fields) + {} + + static DeconstructedPat make_wildcard (location_t locus) + { + return DeconstructedPat (Constructor::make_wildcard (), locus); + } + + static DeconstructedPat make_reference (location_t locus) + { + return DeconstructedPat (Constructor::make_reference (), locus); + } + + const Constructor &get_ctor () const { return ctor; } + + int get_arity () const { return arity; } + + std::vector<DeconstructedPat> specialize (const Constructor &other_ctor, + int other_ctor_arity) const; + + std::string to_string () const; + +private: + DeconstructedPat (Constructor ctor, location_t locus) + : ctor (ctor), arity (0), locus (locus) + {} + + Constructor ctor; + int arity; + std::vector<DeconstructedPat> fields; + location_t locus; +}; + +class PatOrWild +{ +public: + static PatOrWild make_pattern (DeconstructedPat pat) + { + return PatOrWild (pat); + } + + static PatOrWild make_wildcard () { return PatOrWild ({}); } + + bool is_wildcard () const + { + return !(pat.has_value () && !pat.value ().get_ctor ().is_wildcard ()); + } + + bool is_covered_by (const Constructor &c) const; + + // Returns the pattern if it is not a wildcard. + const tl::optional<DeconstructedPat> &get_pat () const + { + rust_assert (pat.has_value ()); + return pat; + } + + Constructor ctor () const + { + if (pat.has_value ()) + return pat.value ().get_ctor (); + else + return Constructor::make_wildcard (); + } + + std::vector<PatOrWild> specialize (const Constructor &other_ctor, + int other_ctor_arity) const; + + std::string to_string () const; + +private: + PatOrWild (tl::optional<DeconstructedPat> pat) : pat (pat) {} + + tl::optional<DeconstructedPat> pat; +}; + +class PatStack +{ +public: + PatStack () : relevant (false) {} + + void push (PatOrWild pat) { pats.push_back (pat); } + + bool empty () const { return pats.empty (); } + + PatOrWild &head () + { + rust_assert (!pats.empty ()); + return pats.front (); + } + + const PatOrWild &head () const + { + rust_assert (!pats.empty ()); + return pats.front (); + } + + // Only called if the head is a constructor which is convered by o. + void pop_head_constructor (const Constructor &other_ctor, + int other_ctor_arity); + + const std::deque<PatOrWild> &get_subpatterns () const { return pats; } + +private: + void pop_head () { pats.pop_front (); } + + std::deque<PatOrWild> pats; + bool relevant; +}; + +class MatrixRow +{ +public: + MatrixRow (PatStack pats, bool is_under_guard_) + : pats (pats), is_under_guard_ (is_under_guard_) + // useful (false), + // head_is_branch (false), + {} + + PatStack &get_pats () { return pats; } + + PatStack get_pats_clone () const { return pats; } + + const PatOrWild &head () const { return pats.head (); } + PatOrWild &head () { return pats.head (); } + + bool is_under_guard () const { return is_under_guard_; } + + std::string to_string () const; + +private: + PatStack pats; + bool is_under_guard_; + // TODO: manage usefulness +}; + +class PlaceInfo +{ +public: + PlaceInfo (TyTy::BaseType *ty) : ty (ty) {} + + TyTy::BaseType *get_type () const { return ty; } + + std::vector<PlaceInfo> specialize (const Constructor &c) const; + +private: + TyTy::BaseType *ty; +}; + +class Matrix +{ +public: + Matrix (std::vector<MatrixRow> rows, std::vector<PlaceInfo> place_infos) + : rows (rows), place_infos (place_infos) + {} + + Matrix () {} + + std::vector<MatrixRow> &get_rows () { return rows; } + + void push_row (const MatrixRow &row) { rows.push_back (row); } + + std::vector<PlaceInfo> &get_place_infos () { return place_infos; } + + std::vector<PatOrWild> heads () const + { + std::vector<PatOrWild> ret; + for (const MatrixRow &row : rows) + ret.push_back (row.head ()); + + return ret; + } + + Matrix specialize (const Constructor &ctor) const; + + std::string to_string () const; + +private: + std::vector<MatrixRow> rows; + std::vector<PlaceInfo> place_infos; +}; + +class MatchArm +{ +public: + MatchArm (DeconstructedPat pat, bool has_guard_) + : pat (pat), has_guard_ (has_guard_) + {} + + DeconstructedPat get_pat () const { return pat; } + + bool has_guard () const { return has_guard_; } + +private: + DeconstructedPat pat; + bool has_guard_; +}; + +class WitnessPat +{ +public: + WitnessPat (Constructor ctor, std::vector<WitnessPat> fields, + TyTy::BaseType *ty) + : ctor (ctor), fields (fields), ty (ty) + {} + + static WitnessPat make_wildcard (TyTy::BaseType *ty) + { + return WitnessPat (Constructor::make_wildcard (), {}, ty); + } + + const Constructor &get_ctor () const { return ctor; } + + const std::vector<WitnessPat> &get_fields () const { return fields; } + + TyTy::BaseType *get_type () const { return ty; } + + std::string to_string () const; + +private: + Constructor ctor; + std::vector<WitnessPat> fields; + TyTy::BaseType *ty; +}; + +class WitnessMatrix +{ +public: + // Create an empty witness matrix. + static WitnessMatrix make_empty () { return WitnessMatrix ({}); } + + // Create a unit witness matrix, a new single witness. + static WitnessMatrix make_unit () + { + return WitnessMatrix ({std::vector<WitnessPat> ()}); + } + + bool empty () const { return patstacks.empty (); } + + const std::vector<std::vector<WitnessPat>> &get_stacks () const + { + return patstacks; + } + + // Reverses specialization. + void apply_constructor (const Constructor &ctor, + const std::set<Constructor> &missings, + TyTy::BaseType *ty); + + void extend (const WitnessMatrix &other); + +private: + WitnessMatrix (std::vector<std::vector<WitnessPat>> patstacks) + : patstacks (patstacks) + {} + + std::vector<std::vector<WitnessPat>> patstacks; +}; + +} // namespace Analysis +} // namespace Rust + +#endif diff --git a/gcc/rust/checks/errors/rust-readonly-check.cc b/gcc/rust/checks/errors/rust-readonly-check.cc index b899898..c128933 100644 --- a/gcc/rust/checks/errors/rust-readonly-check.cc +++ b/gcc/rust/checks/errors/rust-readonly-check.cc @@ -19,10 +19,13 @@ #include "rust-readonly-check.h" #include "rust-tree.h" #include "rust-gcc.h" +#include "print-tree.h" namespace Rust { namespace Analysis { +static std::map<tree, int> assignment_map = {}; + // ported over from c-family/c-warn.cc void readonly_error (location_t loc, tree arg, enum lvalue_use use) @@ -106,37 +109,68 @@ readonly_error (location_t loc, tree arg, enum lvalue_use use) } static void -check_decl (tree *t) +emit_error (tree *t, tree lhs, enum lvalue_use use) { - if (TREE_CODE (*t) == MODIFY_EXPR) + readonly_error (EXPR_LOCATION (*t), lhs, use); + TREE_OPERAND (*t, 0) = error_mark_node; +} + +static void +check_modify_expr (tree *t) +{ + tree lhs = TREE_OPERAND (*t, 0); + if (TREE_CODE (lhs) == ARRAY_REF || TREE_CODE (lhs) == COMPONENT_REF) + lhs = TREE_OPERAND (lhs, 0); + + tree lhs_type = TREE_TYPE (lhs); + if (TYPE_READONLY (lhs_type) || TREE_READONLY (lhs) || TREE_CONSTANT (lhs)) { - tree lhs = TREE_OPERAND (*t, 0); - if (TREE_READONLY (lhs) || TREE_CONSTANT (lhs)) + if (TREE_CODE (lhs) != VAR_DECL) + emit_error (t, lhs, lv_assign); + else if (!DECL_ARTIFICIAL (lhs)) { - readonly_error (EXPR_LOCATION (*t), lhs, lv_assign); - TREE_OPERAND (*t, 0) = error_mark_node; + if (DECL_INITIAL (lhs) != NULL) + emit_error (t, lhs, lv_assign); + else + { + if (assignment_map.find (lhs) == assignment_map.end ()) + { + assignment_map.insert ({lhs, 0}); + } + assignment_map[lhs]++; + + if (assignment_map[lhs] > 1) + emit_error (t, lhs, lv_assign); + } } } } -static tree -readonly_walk_fn (tree *t, int *, void *) +static void +check_decl (tree *t) { switch (TREE_CODE (*t)) { case MODIFY_EXPR: - check_decl (t); + check_modify_expr (t); break; default: break; } +} + +static tree +readonly_walk_fn (tree *t, int *, void *) +{ + check_decl (t); return NULL_TREE; } void ReadonlyCheck::Lint (Compile::Context &ctx) { + assignment_map.clear (); for (auto &fndecl : ctx.get_func_decls ()) { for (tree p = DECL_ARGUMENTS (fndecl); p != NULL_TREE; p = DECL_CHAIN (p)) @@ -148,12 +182,14 @@ ReadonlyCheck::Lint (Compile::Context &ctx) &readonly_walk_fn, &ctx); } + assignment_map.clear (); for (auto &var : ctx.get_var_decls ()) { tree decl = var->get_decl (); check_decl (&decl); } + assignment_map.clear (); for (auto &const_decl : ctx.get_const_decls ()) { check_decl (&const_decl); diff --git a/gcc/rust/checks/errors/rust-unsafe-checker.cc b/gcc/rust/checks/errors/rust-unsafe-checker.cc index c6ed922..46eef11 100644 --- a/gcc/rust/checks/errors/rust-unsafe-checker.cc +++ b/gcc/rust/checks/errors/rust-unsafe-checker.cc @@ -23,6 +23,10 @@ #include "rust-hir-item.h" #include "rust-attribute-values.h" #include "rust-system.h" +#include "rust-immutable-name-resolution-context.h" + +// for flag_name_resolution_2_0 +#include "options.h" namespace Rust { namespace HIR { @@ -216,8 +220,23 @@ UnsafeChecker::visit (PathInExpression &path) NodeId ast_node_id = path.get_mappings ().get_nodeid (); NodeId ref_node_id; - if (!resolver.lookup_resolved_name (ast_node_id, &ref_node_id)) - return; + if (flag_name_resolution_2_0) + { + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); + + auto resolved = nr_ctx.lookup (ast_node_id); + + if (!resolved.has_value ()) + return; + + ref_node_id = resolved.value (); + } + else + { + if (!resolver.lookup_resolved_name (ast_node_id, &ref_node_id)) + return; + } if (auto definition_id = mappings.lookup_node_to_hir (ref_node_id)) { @@ -260,14 +279,14 @@ UnsafeChecker::visit (LiteralExpr &) void UnsafeChecker::visit (BorrowExpr &expr) { - expr.get_expr ()->accept_vis (*this); + expr.get_expr ().accept_vis (*this); } void UnsafeChecker::visit (DereferenceExpr &expr) { TyTy::BaseType *to_deref_type; - auto to_deref = expr.get_expr ()->get_mappings ().get_hirid (); + auto to_deref = expr.get_expr ().get_mappings ().get_hirid (); rust_assert (context.lookup_type (to_deref, &to_deref_type)); @@ -280,60 +299,60 @@ UnsafeChecker::visit (DereferenceExpr &expr) void UnsafeChecker::visit (ErrorPropagationExpr &expr) { - expr.get_expr ()->accept_vis (*this); + expr.get_expr ().accept_vis (*this); } void UnsafeChecker::visit (NegationExpr &expr) { - expr.get_expr ()->accept_vis (*this); + expr.get_expr ().accept_vis (*this); } void UnsafeChecker::visit (ArithmeticOrLogicalExpr &expr) { - expr.get_lhs ()->accept_vis (*this); - expr.get_rhs ()->accept_vis (*this); + expr.get_lhs ().accept_vis (*this); + expr.get_rhs ().accept_vis (*this); } void UnsafeChecker::visit (ComparisonExpr &expr) { - expr.get_lhs ()->accept_vis (*this); - expr.get_rhs ()->accept_vis (*this); + expr.get_lhs ().accept_vis (*this); + expr.get_rhs ().accept_vis (*this); } void UnsafeChecker::visit (LazyBooleanExpr &expr) { - expr.get_lhs ()->accept_vis (*this); - expr.get_rhs ()->accept_vis (*this); + expr.get_lhs ().accept_vis (*this); + expr.get_rhs ().accept_vis (*this); } void UnsafeChecker::visit (TypeCastExpr &expr) { - expr.get_expr ()->accept_vis (*this); + expr.get_expr ().accept_vis (*this); } void UnsafeChecker::visit (AssignmentExpr &expr) { - expr.get_lhs ()->accept_vis (*this); - expr.get_rhs ()->accept_vis (*this); + expr.get_lhs ().accept_vis (*this); + expr.get_rhs ().accept_vis (*this); } void UnsafeChecker::visit (CompoundAssignmentExpr &expr) { - expr.get_lhs ()->accept_vis (*this); - expr.get_rhs ()->accept_vis (*this); + expr.get_lhs ().accept_vis (*this); + expr.get_rhs ().accept_vis (*this); } void UnsafeChecker::visit (GroupedExpr &expr) { - expr.get_expr_in_parens ()->accept_vis (*this); + expr.get_expr_in_parens ().accept_vis (*this); } void @@ -346,20 +365,20 @@ UnsafeChecker::visit (ArrayElemsValues &elems) void UnsafeChecker::visit (ArrayElemsCopied &elems) { - elems.get_elem_to_copy ()->accept_vis (*this); + elems.get_elem_to_copy ().accept_vis (*this); } void UnsafeChecker::visit (ArrayExpr &expr) { - expr.get_internal_elements ()->accept_vis (*this); + expr.get_internal_elements ().accept_vis (*this); } void UnsafeChecker::visit (ArrayIndexExpr &expr) { - expr.get_array_expr ()->accept_vis (*this); - expr.get_index_expr ()->accept_vis (*this); + expr.get_array_expr ().accept_vis (*this); + expr.get_index_expr ().accept_vis (*this); } void @@ -372,7 +391,7 @@ UnsafeChecker::visit (TupleExpr &expr) void UnsafeChecker::visit (TupleIndexExpr &expr) { - expr.get_tuple_expr ()->accept_vis (*this); + expr.get_tuple_expr ().accept_vis (*this); } void @@ -386,13 +405,13 @@ UnsafeChecker::visit (StructExprFieldIdentifier &) void UnsafeChecker::visit (StructExprFieldIdentifierValue &field) { - field.get_value ()->accept_vis (*this); + field.get_value ().accept_vis (*this); } void UnsafeChecker::visit (StructExprFieldIndexValue &field) { - field.get_value ()->accept_vis (*this); + field.get_value ().accept_vis (*this); } void @@ -409,17 +428,32 @@ UnsafeChecker::visit (StructExprStructBase &) void UnsafeChecker::visit (CallExpr &expr) { - if (!expr.get_fnexpr ()) + if (!expr.has_fnexpr ()) return; - NodeId ast_node_id = expr.get_fnexpr ()->get_mappings ().get_nodeid (); + NodeId ast_node_id = expr.get_fnexpr ().get_mappings ().get_nodeid (); NodeId ref_node_id; // There are no unsafe types, and functions are defined in the name resolver. // If we can't find the name, then we're dealing with a type and should return // early. - if (!resolver.lookup_resolved_name (ast_node_id, &ref_node_id)) - return; + if (flag_name_resolution_2_0) + { + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); + + auto resolved = nr_ctx.lookup (ast_node_id); + + if (!resolved.has_value ()) + return; + + ref_node_id = resolved.value (); + } + else + { + if (!resolver.lookup_resolved_name (ast_node_id, &ref_node_id)) + return; + } if (auto definition_id = mappings.lookup_node_to_hir (ref_node_id)) { @@ -447,15 +481,20 @@ UnsafeChecker::visit (MethodCallExpr &expr) TyTy::BaseType *method_type; context.lookup_type (expr.get_method_name ().get_mappings ().get_hirid (), &method_type); + if (!method_type || !method_type->is<TyTy::FnType> ()) + return; - auto fn = *static_cast<TyTy::FnType *> (method_type); + auto &fn = static_cast<TyTy::FnType &> (*method_type); + // FIXME + // should probably use the defid lookup instead + // tl::optional<HIR::Item *> lookup_defid (DefId id); auto method = mappings.lookup_hir_implitem (fn.get_ref ()); if (!unsafe_context.is_in_context () && method) check_unsafe_call (static_cast<Function *> (method->first), expr.get_locus (), "method"); - expr.get_receiver ()->accept_vis (*this); + expr.get_receiver ().accept_vis (*this); for (auto &arg : expr.get_arguments ()) arg->accept_vis (*this); @@ -464,14 +503,14 @@ UnsafeChecker::visit (MethodCallExpr &expr) void UnsafeChecker::visit (FieldAccessExpr &expr) { - expr.get_receiver_expr ()->accept_vis (*this); + expr.get_receiver_expr ().accept_vis (*this); if (unsafe_context.is_in_context ()) return; TyTy::BaseType *receiver_ty; auto ok = context.lookup_type ( - expr.get_receiver_expr ()->get_mappings ().get_hirid (), &receiver_ty); + expr.get_receiver_expr ().get_mappings ().get_hirid (), &receiver_ty); rust_assert (ok); if (receiver_ty->get_kind () == TyTy::TypeKind::ADT) @@ -487,7 +526,7 @@ UnsafeChecker::visit (FieldAccessExpr &expr) void UnsafeChecker::visit (ClosureExpr &expr) { - expr.get_expr ()->accept_vis (*this); + expr.get_expr ().accept_vis (*this); } void @@ -497,7 +536,7 @@ UnsafeChecker::visit (BlockExpr &expr) stmt->accept_vis (*this); if (expr.has_expr ()) - expr.get_final_expr ()->accept_vis (*this); + expr.get_final_expr ().accept_vis (*this); } void @@ -508,26 +547,26 @@ void UnsafeChecker::visit (BreakExpr &expr) { if (expr.has_break_expr ()) - expr.get_expr ()->accept_vis (*this); + expr.get_expr ().accept_vis (*this); } void UnsafeChecker::visit (RangeFromToExpr &expr) { - expr.get_from_expr ()->accept_vis (*this); - expr.get_to_expr ()->accept_vis (*this); + expr.get_from_expr ().accept_vis (*this); + expr.get_to_expr ().accept_vis (*this); } void UnsafeChecker::visit (RangeFromExpr &expr) { - expr.get_from_expr ()->accept_vis (*this); + expr.get_from_expr ().accept_vis (*this); } void UnsafeChecker::visit (RangeToExpr &expr) { - expr.get_to_expr ()->accept_vis (*this); + expr.get_to_expr ().accept_vis (*this); } void @@ -537,21 +576,21 @@ UnsafeChecker::visit (RangeFullExpr &) void UnsafeChecker::visit (RangeFromToInclExpr &expr) { - expr.get_from_expr ()->accept_vis (*this); - expr.get_to_expr ()->accept_vis (*this); + expr.get_from_expr ().accept_vis (*this); + expr.get_to_expr ().accept_vis (*this); } void UnsafeChecker::visit (RangeToInclExpr &expr) { - expr.get_to_expr ()->accept_vis (*this); + expr.get_to_expr ().accept_vis (*this); } void UnsafeChecker::visit (ReturnExpr &expr) { if (expr.has_return_expr ()) - expr.get_expr ()->accept_vis (*this); + expr.get_expr ().accept_vis (*this); } void @@ -559,7 +598,7 @@ UnsafeChecker::visit (UnsafeBlockExpr &expr) { unsafe_context.enter (expr.get_mappings ().get_hirid ()); - expr.get_block_expr ()->accept_vis (*this); + expr.get_block_expr ().accept_vis (*this); unsafe_context.exit (); } @@ -567,61 +606,45 @@ UnsafeChecker::visit (UnsafeBlockExpr &expr) void UnsafeChecker::visit (LoopExpr &expr) { - expr.get_loop_block ()->accept_vis (*this); + expr.get_loop_block ().accept_vis (*this); } void UnsafeChecker::visit (WhileLoopExpr &expr) { - expr.get_predicate_expr ()->accept_vis (*this); - expr.get_loop_block ()->accept_vis (*this); + expr.get_predicate_expr ().accept_vis (*this); + expr.get_loop_block ().accept_vis (*this); } void UnsafeChecker::visit (WhileLetLoopExpr &expr) { - expr.get_cond ()->accept_vis (*this); - expr.get_loop_block ()->accept_vis (*this); + expr.get_cond ().accept_vis (*this); + expr.get_loop_block ().accept_vis (*this); } void UnsafeChecker::visit (IfExpr &expr) { - expr.get_if_condition ()->accept_vis (*this); - expr.get_if_block ()->accept_vis (*this); + expr.get_if_condition ().accept_vis (*this); + expr.get_if_block ().accept_vis (*this); } void UnsafeChecker::visit (IfExprConseqElse &expr) { - expr.get_if_condition ()->accept_vis (*this); - expr.get_if_block ()->accept_vis (*this); - expr.get_else_block ()->accept_vis (*this); -} - -void -UnsafeChecker::visit (IfLetExpr &expr) -{ - expr.get_scrutinee_expr ()->accept_vis (*this); - expr.get_if_block ()->accept_vis (*this); -} - -void -UnsafeChecker::visit (IfLetExprConseqElse &expr) -{ - expr.get_scrutinee_expr ()->accept_vis (*this); - expr.get_if_block ()->accept_vis (*this); - - // TODO: Visit else expression + expr.get_if_condition ().accept_vis (*this); + expr.get_if_block ().accept_vis (*this); + expr.get_else_block ().accept_vis (*this); } void UnsafeChecker::visit (MatchExpr &expr) { - expr.get_scrutinee_expr ()->accept_vis (*this); + expr.get_scrutinee_expr ().accept_vis (*this); for (auto &match_arm : expr.get_match_cases ()) - match_arm.get_expr ()->accept_vis (*this); + match_arm.get_expr ().accept_vis (*this); } void @@ -648,6 +671,17 @@ UnsafeChecker::visit (InlineAsm &expr) } void +UnsafeChecker::visit (LlvmInlineAsm &expr) +{ + if (unsafe_context.is_in_context ()) + return; + + rust_error_at ( + expr.get_locus (), ErrorCode::E0133, + "use of inline assembly is unsafe and requires unsafe function or block"); +} + +void UnsafeChecker::visit (TypeParam &) {} @@ -698,7 +732,7 @@ UnsafeChecker::visit (Function &function) if (is_unsafe_fn) unsafe_context.enter (function.get_mappings ().get_hirid ()); - function.get_definition ()->accept_vis (*this); + function.get_definition ().accept_vis (*this); if (is_unsafe_fn) unsafe_context.exit (); @@ -746,27 +780,27 @@ UnsafeChecker::visit (Union &) void UnsafeChecker::visit (ConstantItem &const_item) { - const_item.get_expr ()->accept_vis (*this); + const_item.get_expr ().accept_vis (*this); } void UnsafeChecker::visit (StaticItem &static_item) { - static_item.get_expr ()->accept_vis (*this); + static_item.get_expr ().accept_vis (*this); } void UnsafeChecker::visit (TraitItemFunc &item) { - if (item.has_block_defined ()) - item.get_block_expr ()->accept_vis (*this); + if (item.has_definition ()) + item.get_block_expr ().accept_vis (*this); } void UnsafeChecker::visit (TraitItemConst &item) { if (item.has_expr ()) - item.get_expr ()->accept_vis (*this); + item.get_expr ().accept_vis (*this); } void @@ -784,7 +818,23 @@ UnsafeChecker::visit (Trait &trait) void UnsafeChecker::visit (ImplBlock &impl) { - // FIXME: Handle unsafe impls + bool safe = !impl.is_unsafe (); + // Check for unsafe-only attributes on generics and lifetimes + if (safe) + for (auto &parm : impl.get_generic_params ()) + { + for (auto o_attr : parm->get_outer_attrs ()) + { + rust_assert (!o_attr.is_inner_attribute ()); + + Rust::AST::SimplePath path = o_attr.get_path (); + if (path == Values::Attributes::MAY_DANGLE) + rust_error_at ( + o_attr.get_locus (), ErrorCode::E0569, + "use of %<may_dangle%> is unsafe and requires unsafe impl"); + } + } + for (auto &item : impl.get_impl_items ()) item->accept_vis (*this); } @@ -897,13 +947,13 @@ void UnsafeChecker::visit (LetStmt &stmt) { if (stmt.has_init_expr ()) - stmt.get_init_expr ()->accept_vis (*this); + stmt.get_init_expr ().accept_vis (*this); } void UnsafeChecker::visit (ExprStmt &stmt) { - stmt.get_expr ()->accept_vis (*this); + stmt.get_expr ().accept_vis (*this); } void @@ -923,10 +973,6 @@ UnsafeChecker::visit (ParenthesisedType &) {} void -UnsafeChecker::visit (ImplTraitTypeOneBound &) -{} - -void UnsafeChecker::visit (TupleType &) {} diff --git a/gcc/rust/checks/errors/rust-unsafe-checker.h b/gcc/rust/checks/errors/rust-unsafe-checker.h index 1fa1fe0..9a8fb7c 100644 --- a/gcc/rust/checks/errors/rust-unsafe-checker.h +++ b/gcc/rust/checks/errors/rust-unsafe-checker.h @@ -110,12 +110,11 @@ private: virtual void visit (WhileLetLoopExpr &expr) override; virtual void visit (IfExpr &expr) override; virtual void visit (IfExprConseqElse &expr) override; - virtual void visit (IfLetExpr &expr) override; - virtual void visit (IfLetExprConseqElse &expr) override; virtual void visit (MatchExpr &expr) override; virtual void visit (AwaitExpr &expr) override; virtual void visit (AsyncBlockExpr &expr) override; - virtual void visit (InlineAsm &expr); + virtual void visit (InlineAsm &expr) override; + virtual void visit (LlvmInlineAsm &expr) override; virtual void visit (TypeParam ¶m) override; virtual void visit (ConstGenericParam ¶m) override; virtual void visit (LifetimeWhereClauseItem &item) override; @@ -174,7 +173,6 @@ private: virtual void visit (ImplTraitType &type) override; virtual void visit (TraitObjectType &type) override; virtual void visit (ParenthesisedType &type) override; - virtual void visit (ImplTraitTypeOneBound &type) override; virtual void visit (TupleType &type) override; virtual void visit (NeverType &type) override; virtual void visit (RawPointerType &type) override; diff --git a/gcc/rust/checks/lints/rust-lint-marklive.cc b/gcc/rust/checks/lints/rust-lint-marklive.cc index 24df933..af7535a 100644 --- a/gcc/rust/checks/lints/rust-lint-marklive.cc +++ b/gcc/rust/checks/lints/rust-lint-marklive.cc @@ -22,6 +22,8 @@ #include "rust-lint-marklive.h" #include "options.h" #include "rust-hir-full.h" +#include "rust-hir-map.h" +#include "rust-hir-path.h" #include "rust-name-resolver.h" #include "rust-immutable-name-resolution-context.h" #include "rust-system.h" @@ -99,15 +101,21 @@ MarkLive::visit (HIR::PathInExpression &expr) { // We should iterate every path segment in order to mark the struct which // is used in expression like Foo::bar(), we should mark the Foo alive. - expr.iterate_path_segments ([&] (HIR::PathExprSegment &seg) -> bool { - return visit_path_segment (seg); - }); + if (!expr.is_lang_item ()) + expr.iterate_path_segments ([&] (HIR::PathExprSegment &seg) -> bool { + return visit_path_segment (seg); + }); // after iterate the path segments, we should mark functions and associated // functions alive. NodeId ast_node_id = expr.get_mappings ().get_nodeid (); NodeId ref_node_id = UNKNOWN_NODEID; - find_ref_node_id (ast_node_id, ref_node_id); + + if (expr.is_lang_item ()) + ref_node_id + = Analysis::Mappings::get ().get_lang_item_node (expr.get_lang_item ()); + else + find_ref_node_id (ast_node_id, ref_node_id); // node back to HIR tl::optional<HirId> hid = mappings.lookup_node_to_hir (ref_node_id); @@ -124,7 +132,7 @@ MarkLive::visit (HIR::PathInExpression &expr) void MarkLive::visit (HIR::MethodCallExpr &expr) { - expr.get_receiver ()->accept_vis (*this); + expr.get_receiver ().accept_vis (*this); visit_path_segment (expr.get_method_name ()); for (auto &argument : expr.get_arguments ()) argument->accept_vis (*this); @@ -155,7 +163,17 @@ MarkLive::visit_path_segment (HIR::PathExprSegment seg) // // We should mark them alive all and ignoring other kind of segments. // If the segment we dont care then just return false is fine - if (!resolver->lookup_resolved_name (ast_node_id, &ref_node_id)) + if (flag_name_resolution_2_0) + { + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); + + if (auto id = nr_ctx.lookup (ast_node_id)) + ref_node_id = *id; + else + return false; + } + else if (!resolver->lookup_resolved_name (ast_node_id, &ref_node_id)) { if (!resolver->lookup_resolved_type (ast_node_id, &ref_node_id)) return false; @@ -172,14 +190,14 @@ void MarkLive::visit (HIR::FieldAccessExpr &expr) { // visit receiver at first - expr.get_receiver_expr ()->accept_vis (*this); + expr.get_receiver_expr ().accept_vis (*this); // resolve the receiver back to ADT type TyTy::BaseType *receiver = nullptr; if (!tyctx->lookup_type ( - expr.get_receiver_expr ()->get_mappings ().get_hirid (), &receiver)) + expr.get_receiver_expr ().get_mappings ().get_hirid (), &receiver)) { - rust_error_at (expr.get_receiver_expr ()->get_locus (), + rust_error_at (expr.get_receiver_expr ().get_locus (), "unresolved type for receiver"); } @@ -211,7 +229,7 @@ MarkLive::visit (HIR::FieldAccessExpr &expr) rust_assert (ok); if (index >= variant->num_fields ()) { - rust_error_at (expr.get_receiver_expr ()->get_locus (), + rust_error_at (expr.get_receiver_expr ().get_locus (), "cannot access struct %s by index: %lu", adt->get_name ().c_str (), (unsigned long) index); return; @@ -226,15 +244,28 @@ void MarkLive::visit (HIR::TupleIndexExpr &expr) { // TODO: unused tuple field detection - expr.get_tuple_expr ()->accept_vis (*this); + expr.get_tuple_expr ().accept_vis (*this); } void MarkLive::visit (HIR::TypeAlias &alias) { - NodeId ast_node_id; - resolver->lookup_resolved_type ( - alias.get_type_aliased ()->get_mappings ().get_nodeid (), &ast_node_id); + NodeId ast_node_id = UNKNOWN_NODEID; + if (flag_name_resolution_2_0) + { + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); + + if (auto id = nr_ctx.lookup ( + alias.get_type_aliased ().get_mappings ().get_nodeid ())) + ast_node_id = *id; + } + else + { + resolver->lookup_resolved_type ( + alias.get_type_aliased ().get_mappings ().get_nodeid (), &ast_node_id); + } + if (auto hid = mappings.lookup_node_to_hir (ast_node_id)) mark_hir_id (*hid); else @@ -256,7 +287,7 @@ MarkLive::find_ref_node_id (NodeId ast_node_id, NodeId &ref_node_id) { if (flag_name_resolution_2_0) { - auto nr_ctx + auto &nr_ctx = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); nr_ctx.lookup (ast_node_id).map ([&ref_node_id] (NodeId resolved) { diff --git a/gcc/rust/checks/lints/rust-lint-marklive.h b/gcc/rust/checks/lints/rust-lint-marklive.h index 92b4502..86d96fc 100644 --- a/gcc/rust/checks/lints/rust-lint-marklive.h +++ b/gcc/rust/checks/lints/rust-lint-marklive.h @@ -43,44 +43,44 @@ public: void visit (HIR::BorrowExpr &expr) override { - expr.get_expr ()->accept_vis (*this); + expr.get_expr ().accept_vis (*this); } void visit (HIR::DereferenceExpr &expr) override { - expr.get_expr ()->accept_vis (*this); + expr.get_expr ().accept_vis (*this); } void visit (HIR::NegationExpr &expr) override { - expr.get_expr ()->accept_vis (*this); + expr.get_expr ().accept_vis (*this); } void visit (HIR::LazyBooleanExpr &expr) override { - expr.get_lhs ()->accept_vis (*this); - expr.get_rhs ()->accept_vis (*this); + expr.get_lhs ().accept_vis (*this); + expr.get_rhs ().accept_vis (*this); } void visit (HIR::TypeCastExpr &expr) override { - expr.get_expr ()->accept_vis (*this); + expr.get_expr ().accept_vis (*this); } void visit (HIR::GroupedExpr &expr) override { - expr.get_expr_in_parens ()->accept_vis (*this); + expr.get_expr_in_parens ().accept_vis (*this); } void visit (HIR::ArrayExpr &expr) override { - expr.get_internal_elements ()->accept_vis (*this); + expr.get_internal_elements ().accept_vis (*this); } void visit (HIR::ArrayIndexExpr &expr) override { - expr.get_array_expr ()->accept_vis (*this); - expr.get_index_expr ()->accept_vis (*this); + expr.get_array_expr ().accept_vis (*this); + expr.get_index_expr ().accept_vis (*this); } void visit (HIR::ArrayElemsValues &expr) override @@ -107,57 +107,57 @@ public: } if (expr.has_expr ()) { - expr.get_final_expr ()->accept_vis (*this); + expr.get_final_expr ().accept_vis (*this); } } void visit (HIR::UnsafeBlockExpr &expr) override { - expr.get_block_expr ()->accept_vis (*this); + expr.get_block_expr ().accept_vis (*this); } void visit (HIR::LoopExpr &expr) override { - expr.get_loop_block ()->accept_vis (*this); + expr.get_loop_block ().accept_vis (*this); } void visit (HIR::BreakExpr &expr) override { if (expr.has_break_expr ()) - expr.get_expr ()->accept_vis (*this); + expr.get_expr ().accept_vis (*this); } void visit (HIR::WhileLoopExpr &expr) override { - expr.get_loop_block ()->accept_vis (*this); - expr.get_predicate_expr ()->accept_vis (*this); + expr.get_loop_block ().accept_vis (*this); + expr.get_predicate_expr ().accept_vis (*this); } void visit (HIR::Function &function) override { - function.get_definition ()->accept_vis (*this); + function.get_definition ().accept_vis (*this); } void visit (HIR::ReturnExpr &expr) override { if (expr.has_return_expr ()) - expr.get_expr ()->accept_vis (*this); + expr.get_expr ().accept_vis (*this); } void visit (HIR::WhileLetLoopExpr &expr) override { - expr.get_loop_block ()->accept_vis (*this); - expr.get_cond ()->accept_vis (*this); + expr.get_loop_block ().accept_vis (*this); + expr.get_cond ().accept_vis (*this); } void visit (HIR::ExprStmt &stmt) override { - stmt.get_expr ()->accept_vis (*this); + stmt.get_expr ().accept_vis (*this); } void visit (HIR::CallExpr &expr) override { - expr.get_fnexpr ()->accept_vis (*this); + expr.get_fnexpr ().accept_vis (*this); for (auto &argument : expr.get_arguments ()) argument->accept_vis (*this); } @@ -169,8 +169,8 @@ public: } void visit (HIR::ComparisonExpr &expr) override { - expr.get_lhs ()->accept_vis (*this); - expr.get_rhs ()->accept_vis (*this); + expr.get_lhs ().accept_vis (*this); + expr.get_rhs ().accept_vis (*this); } void visit (HIR::AssignmentExpr &expr) override @@ -187,33 +187,33 @@ public: void visit (HIR::IfExpr &expr) override { - expr.get_if_condition ()->accept_vis (*this); - expr.get_if_block ()->accept_vis (*this); + expr.get_if_condition ().accept_vis (*this); + expr.get_if_block ().accept_vis (*this); } void visit (HIR::IfExprConseqElse &expr) override { - expr.get_if_condition ()->accept_vis (*this); - expr.get_if_block ()->accept_vis (*this); - expr.get_else_block ()->accept_vis (*this); + expr.get_if_condition ().accept_vis (*this); + expr.get_if_block ().accept_vis (*this); + expr.get_else_block ().accept_vis (*this); } void visit (HIR::MatchExpr &expr) override { - expr.get_scrutinee_expr ()->accept_vis (*this); + expr.get_scrutinee_expr ().accept_vis (*this); std::vector<HIR::MatchCase> &cases = expr.get_match_cases (); for (auto &&caz : cases) { auto case_arm = caz.get_arm (); if (case_arm.has_match_arm_guard ()) - case_arm.get_guard_expr ()->accept_vis (*this); - caz.get_expr ()->accept_vis (*this); + case_arm.get_guard_expr ().accept_vis (*this); + caz.get_expr ().accept_vis (*this); } } void visit (HIR::TraitItemFunc &item) override { - item.get_block_expr ()->accept_vis (*this); + item.get_block_expr ().accept_vis (*this); } void visit (HIR::ImplBlock &impl) override @@ -228,7 +228,7 @@ public: { if (stmt.has_init_expr ()) { - stmt.get_init_expr ()->accept_vis (*this); + stmt.get_init_expr ().accept_vis (*this); } } @@ -247,18 +247,18 @@ public: stct.get_struct_name ().accept_vis (*this); if (stct.has_struct_base ()) { - stct.struct_base->base_struct->accept_vis (*this); + stct.get_struct_base ().get_base ().accept_vis (*this); } } virtual void visit (HIR::StructExprFieldIdentifierValue &field) override { - field.get_value ()->accept_vis (*this); + field.get_value ().accept_vis (*this); } void visit (HIR::StructExprStructBase &stct) override { - stct.get_struct_base ()->base_struct->accept_vis (*this); + stct.get_struct_base ().get_base ().accept_vis (*this); } void visit (HIR::Module &module) override @@ -269,7 +269,7 @@ public: void visit (HIR::ClosureExpr &expr) override { - expr.get_expr ()->accept_vis (*this); + expr.get_expr ().accept_vis (*this); } private: diff --git a/gcc/rust/checks/lints/rust-lint-scan-deadcode.h b/gcc/rust/checks/lints/rust-lint-scan-deadcode.h index e6ef1392..0fc203b 100644 --- a/gcc/rust/checks/lints/rust-lint-scan-deadcode.h +++ b/gcc/rust/checks/lints/rust-lint-scan-deadcode.h @@ -93,7 +93,8 @@ public: { HirId field_hir_id = field.get_mappings ().get_hirid (); if (should_warn (field_hir_id) - && !field.get_visibility ().is_public ()) + && !field.get_visibility ().is_public () + && field.get_field_name ().as_string ().at (0) != '_') { rust_warning_at (field.get_locus (), 0, "field is never read: %qs", diff --git a/gcc/rust/expand/rust-cfg-strip.cc b/gcc/rust/expand/rust-cfg-strip.cc index 8abc5cb..a8c3ca5 100644 --- a/gcc/rust/expand/rust-cfg-strip.cc +++ b/gcc/rust/expand/rust-cfg-strip.cc @@ -19,6 +19,7 @@ #include "rust-cfg-strip.h" #include "rust-ast-full.h" #include "rust-ast-visitor.h" +#include "rust-path.h" #include "rust-session-manager.h" #include "rust-attribute-values.h" @@ -195,6 +196,26 @@ CfgStrip::maybe_strip_struct_fields (std::vector<AST::StructField> &fields) } void +CfgStrip::maybe_strip_struct_expr_fields ( + std::vector<std::unique_ptr<AST::StructExprField>> &fields) +{ + for (auto it = fields.begin (); it != fields.end ();) + { + auto &field = *it; + + auto &field_attrs = field->get_outer_attrs (); + expand_cfg_attrs (field_attrs); + if (fails_cfg_with_expand (field_attrs)) + { + it = fields.erase (it); + continue; + } + + ++it; + } +} + +void CfgStrip::maybe_strip_tuple_fields (std::vector<AST::TupleField> &fields) { for (auto it = fields.begin (); it != fields.end ();) @@ -414,10 +435,13 @@ CfgStrip::visit (AST::PathInExpression &path) return; } - for (auto &segment : path.get_segments ()) + if (!path.is_lang_item ()) { - if (segment.has_generic_args ()) - maybe_strip_generic_args (segment.get_generic_args ()); + for (auto &segment : path.get_segments ()) + { + if (segment.has_generic_args ()) + maybe_strip_generic_args (segment.get_generic_args ()); + } } } @@ -962,6 +986,8 @@ CfgStrip::visit (AST::StructExprStructFields &expr) "cannot strip expression in this position - outer " "attributes not allowed"); } + + maybe_strip_struct_expr_fields (expr.get_fields ()); } void @@ -1852,6 +1878,10 @@ CfgStrip::visit (AST::StructStruct &struct_item) } AST::DefaultASTVisitor::visit (struct_item); + + /* strip struct fields if required - this is presumably + * allowed by spec */ + maybe_strip_struct_fields (struct_item.get_fields ()); } void CfgStrip::visit (AST::TupleStruct &tuple_struct) diff --git a/gcc/rust/expand/rust-cfg-strip.h b/gcc/rust/expand/rust-cfg-strip.h index 773bfde..4900ae8 100644 --- a/gcc/rust/expand/rust-cfg-strip.h +++ b/gcc/rust/expand/rust-cfg-strip.h @@ -36,6 +36,8 @@ public: void go (AST::Crate &crate); void maybe_strip_struct_fields (std::vector<AST::StructField> &fields); + void maybe_strip_struct_expr_fields ( + std::vector<std::unique_ptr<AST::StructExprField>> &fields); void maybe_strip_tuple_fields (std::vector<AST::TupleField> &fields); void maybe_strip_function_params ( std::vector<std::unique_ptr<AST::Param>> ¶ms); diff --git a/gcc/rust/expand/rust-derive-clone.cc b/gcc/rust/expand/rust-derive-clone.cc index 2f2554d..321fa00 100644 --- a/gcc/rust/expand/rust-derive-clone.cc +++ b/gcc/rust/expand/rust-derive-clone.cc @@ -17,7 +17,12 @@ // <http://www.gnu.org/licenses/>. #include "rust-derive-clone.h" +#include "rust-ast.h" +#include "rust-expr.h" #include "rust-item.h" +#include "rust-path.h" +#include "rust-pattern.h" +#include "rust-system.h" namespace Rust { namespace AST { @@ -28,6 +33,15 @@ DeriveClone::clone_call (std::unique_ptr<Expr> &&to_clone) // $crate::core::clone::Clone::clone for the fully qualified path - we don't // link with `core` yet so that might be an issue. Use `Clone::clone` for now? // TODO: Factor this function inside the DeriveAccumulator + + // Interestingly, later versions of Rust have a `clone_fn` lang item which + // corresponds to this. But because we are first targeting 1.49, we cannot use + // it yet. Once we target a new, more recent version of the language, we'll + // have figured out how to compile and distribute `core`, meaning we'll be + // able to directly call `::core::clone::Clone::clone()` + + // Not sure how to call it properly in the meantime... + auto path = std::unique_ptr<Expr> ( new PathInExpression (builder.path_in_expression ({"Clone", "clone"}))); @@ -47,11 +61,10 @@ std::unique_ptr<AssociatedItem> DeriveClone::clone_fn (std::unique_ptr<Expr> &&clone_expr) { auto block = std::unique_ptr<BlockExpr> ( - new BlockExpr ({}, std::move (clone_expr), {}, {}, AST::LoopLabel::error (), - loc, loc)); + new BlockExpr ({}, std::move (clone_expr), {}, {}, tl::nullopt, loc, loc)); auto big_self_type = builder.single_type_path ("Self"); - std::unique_ptr<SelfParam> self (new SelfParam (Lifetime::error (), + std::unique_ptr<SelfParam> self (new SelfParam (tl::nullopt, /* is_mut */ false, loc)); std::vector<std::unique_ptr<Param>> params; @@ -73,23 +86,23 @@ DeriveClone::clone_fn (std::unique_ptr<Expr> &&clone_expr) * */ std::unique_ptr<Item> -DeriveClone::clone_impl (std::unique_ptr<AssociatedItem> &&clone_fn, - std::string name) +DeriveClone::clone_impl ( + std::unique_ptr<AssociatedItem> &&clone_fn, std::string name, + const std::vector<std::unique_ptr<GenericParam>> &type_generics) { - // should that be `$crate::core::clone::Clone` instead? - auto segments = std::vector<std::unique_ptr<TypePathSegment>> (); - segments.emplace_back (builder.type_path_segment ("Clone")); - auto clone = TypePath (std::move (segments), loc); - - auto trait_items = std::vector<std::unique_ptr<AssociatedItem>> (); - trait_items.emplace_back (std::move (clone_fn)); - - return std::unique_ptr<Item> ( - new TraitImpl (clone, /* unsafe */ false, - /* exclam */ false, std::move (trait_items), - /* generics */ {}, builder.single_type_path (name), - WhereClause::create_empty (), Visibility::create_private (), - {}, {}, loc)); + // we should have two of these, so we don't run into issues with + // two paths sharing a node id + auto clone_bound = builder.type_path (LangItem::Kind::CLONE); + auto clone_trait_path = builder.type_path (LangItem::Kind::CLONE); + + auto trait_items = vec (std::move (clone_fn)); + + auto generics = setup_impl_generics (name, type_generics, + builder.trait_bound (clone_bound)); + + return builder.trait_impl (clone_trait_path, std::move (generics.self_type), + std::move (trait_items), + std::move (generics.impl)); } // TODO: Create new `make_qualified_call` helper function @@ -122,7 +135,8 @@ DeriveClone::visit_tuple (TupleStruct &item) auto constructor = builder.call (std::move (path), std::move (cloned_fields)); expanded = clone_impl (clone_fn (std::move (constructor)), - item.get_identifier ().as_string ()); + item.get_identifier ().as_string (), + item.get_generic_params ()); } void @@ -133,7 +147,8 @@ DeriveClone::visit_struct (StructStruct &item) auto unit_ctor = builder.struct_expr_struct (item.get_struct_name ().as_string ()); expanded = clone_impl (clone_fn (std::move (unit_ctor)), - item.get_struct_name ().as_string ()); + item.get_struct_name ().as_string (), + item.get_generic_params ()); return; } @@ -151,27 +166,226 @@ DeriveClone::visit_struct (StructStruct &item) auto ctor = builder.struct_expr (item.get_struct_name ().as_string (), std::move (cloned_fields)); expanded = clone_impl (clone_fn (std::move (ctor)), - item.get_struct_name ().as_string ()); + item.get_struct_name ().as_string (), + item.get_generic_params ()); +} + +MatchCase +DeriveClone::clone_enum_identifier (PathInExpression variant_path, + const std::unique_ptr<EnumItem> &variant) +{ + auto pattern = std::unique_ptr<Pattern> (new ReferencePattern ( + std::unique_ptr<Pattern> (new PathInExpression ( + variant_path.get_segments (), {}, variant_path.get_locus (), + variant_path.opening_scope_resolution ())), + false, false, loc)); + auto expr = std::unique_ptr<Expr> ( + new PathInExpression (variant_path.get_segments (), {}, + variant_path.get_locus (), + variant_path.opening_scope_resolution ())); + + return builder.match_case (std::move (pattern), std::move (expr)); +} + +MatchCase +DeriveClone::clone_enum_tuple (PathInExpression variant_path, + const EnumItemTuple &variant) +{ + auto patterns = std::vector<std::unique_ptr<Pattern>> (); + auto cloned_patterns = std::vector<std::unique_ptr<Expr>> (); + + for (size_t i = 0; i < variant.get_tuple_fields ().size (); i++) + { + // The pattern we're creating for each field is `self_<i>` where `i` is + // the index of the field. It doesn't actually matter what we use, as long + // as it's ordered, unique, and that we can reuse it in the match case's + // return expression to clone the field. + auto pattern_str = "__self_" + std::to_string (i); + + patterns.emplace_back (builder.identifier_pattern (pattern_str)); + + // Now, for each tuple's element, we create a new expression calling + // `clone` on it for the match case's return expression + cloned_patterns.emplace_back ( + clone_call (builder.ref (builder.identifier (pattern_str)))); + } + + auto pattern_items = std::unique_ptr<TupleStructItems> ( + new TupleStructItemsNoRange (std::move (patterns))); + + auto pattern = std::unique_ptr<Pattern> (new ReferencePattern ( + std::unique_ptr<Pattern> (new TupleStructPattern ( + PathInExpression (variant_path.get_segments (), {}, + variant_path.get_locus (), + variant_path.opening_scope_resolution ()), + std::move (pattern_items))), + false, false, loc)); + + auto expr = builder.call (std::unique_ptr<Expr> (new PathInExpression ( + variant_path.get_segments (), {}, + variant_path.get_locus (), + variant_path.opening_scope_resolution ())), + std::move (cloned_patterns)); + + return builder.match_case (std::move (pattern), std::move (expr)); +} + +MatchCase +DeriveClone::clone_enum_struct (PathInExpression variant_path, + const EnumItemStruct &variant) +{ + auto field_patterns = std::vector<std::unique_ptr<StructPatternField>> (); + auto cloned_fields = std::vector<std::unique_ptr<StructExprField>> (); + +#if 0 + // NOTE: We currently do not support compiling struct patterns where an + // identifier is assigned a new pattern, e.g. Bloop { f0: x } + // This is the code we should eventually produce as it mimics what rustc does + // - which is probably here for a good reason. In the meantime, we can just + // use the field's identifier as the pattern: Bloop { f0 } + // We can then clone the field directly instead of calling `clone()` on the + // new pattern. + // TODO: Figure out if that is actually needed and why rustc does it? + + for (size_t i = 0; i < variant.get_struct_fields ().size (); i++) + { + auto &field = variant.get_struct_fields ()[i]; + + // Just like for tuples, the pattern we're creating for each field is + // `self_<i>` where `i` is the index of the field. It doesn't actually + // matter what we use, as long as it's ordered, unique, and that we can + // reuse it in the match case's return expression to clone the field. + auto pattern_str = "__self_" + std::to_string (i); + + field_patterns.emplace_back ( + std::unique_ptr<StructPatternField> (new StructPatternFieldIdentPat ( + field.get_field_name (), builder.identifier_pattern (pattern_str), {}, + loc))); + + cloned_fields.emplace_back ( + std::unique_ptr<StructExprField> (new StructExprFieldIdentifierValue ( + field.get_field_name (), + clone_call (builder.ref (builder.identifier (pattern_str))), {}, + loc))); + } +#endif + + for (const auto &field : variant.get_struct_fields ()) + { + // We match on the struct's fields, and then recreate an instance of that + // struct, cloning each field + + field_patterns.emplace_back ( + std::unique_ptr<StructPatternField> (new StructPatternFieldIdent ( + field.get_field_name (), false /* is_ref? true? */, false, {}, loc))); + + cloned_fields.emplace_back ( + std::unique_ptr<StructExprField> (new StructExprFieldIdentifierValue ( + field.get_field_name (), + clone_call (builder.ref ( + builder.identifier (field.get_field_name ().as_string ()))), + {}, loc))); + } + + auto pattern_elts = StructPatternElements (std::move (field_patterns)); + + auto pattern = std::unique_ptr<Pattern> ( + new ReferencePattern (std::unique_ptr<Pattern> (new StructPattern ( + variant_path, loc, pattern_elts)), + false, false, loc)); + + PathInExpression new_path (variant_path.get_segments (), + variant_path.get_outer_attrs (), + variant_path.get_locus (), + variant_path.opening_scope_resolution ()); + + auto expr = std::unique_ptr<Expr> ( + new StructExprStructFields (new_path, std::move (cloned_fields), loc)); + + return builder.match_case (std::move (pattern), std::move (expr)); } void DeriveClone::visit_enum (Enum &item) { - rust_sorry_at (item.get_locus (), "cannot derive %qs for these items yet", - "Clone"); + // Create an arm for each variant of the enum: + // - For enum item variants (simple identifiers), just create the same + // variant. + // - For struct and tuple variants, destructure the pattern and call clone for + // each field. + + auto cases = std::vector<MatchCase> (); + + for (const auto &variant : item.get_variants ()) + { + auto path + = builder.variant_path (item.get_identifier ().as_string (), + variant->get_identifier ().as_string ()); + + switch (variant->get_enum_item_kind ()) + { + // Identifiers and discriminated variants are the same for a clone - we + // just return the same variant + case EnumItem::Kind::Identifier: + case EnumItem::Kind::Discriminant: + cases.emplace_back (clone_enum_identifier (path, variant)); + break; + case EnumItem::Kind::Tuple: + cases.emplace_back ( + clone_enum_tuple (path, static_cast<EnumItemTuple &> (*variant))); + break; + case EnumItem::Kind::Struct: + cases.emplace_back ( + clone_enum_struct (path, static_cast<EnumItemStruct &> (*variant))); + break; + } + } + + // match self { ... } + auto match = builder.match (builder.identifier ("self"), std::move (cases)); + + expanded = clone_impl (clone_fn (std::move (match)), + item.get_identifier ().as_string (), + item.get_generic_params ()); } void DeriveClone::visit_union (Union &item) { // FIXME: Should be $crate::core::clone::AssertParamIsCopy (or similar) + // (Rust-GCC#3329) + + auto copy_path = builder.type_path (LangItem::Kind::COPY); + auto sized_path = builder.type_path (LangItem::Kind::SIZED); + + auto copy_bound = std::unique_ptr<TypeParamBound> ( + new TraitBound (copy_path, item.get_locus ())); + auto sized_bound = std::unique_ptr<TypeParamBound> ( + new TraitBound (sized_path, item.get_locus (), false, + true /* opening_question_mark */)); + + auto bounds = vec (std::move (copy_bound), std::move (sized_bound)); + + // struct AssertParamIsCopy<T: Copy + ?Sized> { _t: PhantomData<T> } + auto assert_param_is_copy = "AssertParamIsCopy"; + auto t = std::unique_ptr<GenericParam> ( + new TypeParam (Identifier ("T"), item.get_locus (), std::move (bounds))); + auto assert_param_is_copy_struct = builder.struct_struct ( + assert_param_is_copy, vec (std::move (t)), + {StructField ( + Identifier ("_t"), + builder.single_generic_type_path ( + LangItem::Kind::PHANTOM_DATA, + GenericArgs ( + {}, {GenericArg::create_type (builder.single_type_path ("T"))}, {})), + Visibility::create_private (), item.get_locus ())}); // <Self> auto arg = GenericArg::create_type (builder.single_type_path ("Self")); // AssertParamIsCopy::<Self> auto type = std::unique_ptr<TypePathSegment> ( - new TypePathSegmentGeneric (PathIdentSegment ("AssertParamIsCopy", loc), + new TypePathSegmentGeneric (PathIdentSegment (assert_param_is_copy, loc), false, GenericArgs ({}, {arg}, {}, loc), loc)); auto type_paths = std::vector<std::unique_ptr<TypePathSegment>> (); type_paths.emplace_back (std::move (type)); @@ -179,15 +393,17 @@ DeriveClone::visit_union (Union &item) auto full_path = std::unique_ptr<Type> (new TypePath ({std::move (type_paths)}, loc)); - auto stmts = std::vector<std::unique_ptr<Stmt>> (); - stmts.emplace_back ( - builder.let (builder.wildcard (), std::move (full_path), nullptr)); auto tail_expr = builder.deref (builder.identifier ("self")); + auto stmts + = vec (std::move (assert_param_is_copy_struct), + builder.let (builder.wildcard (), std::move (full_path), nullptr)); + auto block = builder.block (std::move (stmts), std::move (tail_expr)); expanded = clone_impl (clone_fn (std::move (block)), - item.get_identifier ().as_string ()); + item.get_identifier ().as_string (), + item.get_generic_params ()); } } // namespace AST diff --git a/gcc/rust/expand/rust-derive-clone.h b/gcc/rust/expand/rust-derive-clone.h index ab64829..61224ba 100644 --- a/gcc/rust/expand/rust-derive-clone.h +++ b/gcc/rust/expand/rust-derive-clone.h @@ -59,8 +59,26 @@ private: * } * */ - std::unique_ptr<Item> clone_impl (std::unique_ptr<AssociatedItem> &&clone_fn, - std::string name); + std::unique_ptr<Item> + clone_impl (std::unique_ptr<AssociatedItem> &&clone_fn, std::string name, + const std::vector<std::unique_ptr<GenericParam>> &type_generics); + + /** + * Get the path to use for matching and creating a variant when matching on an + * enum. E.g. for the `Option` enum, with the `None` variant, this will create + * a path `Option::None` + */ + PathInExpression variant_match_path (Enum &item, const Identifier &variant); + + /** + * Implementation of clone for all possible variants of an enum + */ + MatchCase clone_enum_identifier (PathInExpression variant_path, + const std::unique_ptr<EnumItem> &variant); + MatchCase clone_enum_tuple (PathInExpression variant_path, + const EnumItemTuple &variant); + MatchCase clone_enum_struct (PathInExpression variant_path, + const EnumItemStruct &variant); virtual void visit_struct (StructStruct &item); virtual void visit_tuple (TupleStruct &item); diff --git a/gcc/rust/expand/rust-derive-copy.cc b/gcc/rust/expand/rust-derive-copy.cc index a1c8ed0..b2971ad 100644 --- a/gcc/rust/expand/rust-derive-copy.cc +++ b/gcc/rust/expand/rust-derive-copy.cc @@ -17,7 +17,8 @@ // <http://www.gnu.org/licenses/>. #include "rust-derive-copy.h" -#include "rust-ast-full.h" +#include "rust-hir-map.h" +#include "rust-path.h" namespace Rust { namespace AST { @@ -37,43 +38,48 @@ DeriveCopy::go (Item &item) } std::unique_ptr<Item> -DeriveCopy::copy_impl (std::string name) +DeriveCopy::copy_impl ( + std::string name, + const std::vector<std::unique_ptr<GenericParam>> &type_generics) { - // `$crate::core::marker::Copy` instead - auto segments = std::vector<std::unique_ptr<TypePathSegment>> (); - segments.emplace_back (builder.type_path_segment ("Copy")); - auto copy = TypePath (std::move (segments), loc); - - return std::unique_ptr<Item> ( - new TraitImpl (copy, /* unsafe */ false, - /* exclam */ false, /* trait items */ {}, - /* generics */ {}, builder.single_type_path (name), - WhereClause::create_empty (), Visibility::create_private (), - {}, {}, loc)); + // we should have two of these, so we don't run into issues with + // two paths sharing a node id + auto copy_bound = builder.type_path (LangItem::Kind::COPY); + auto copy_trait_path = builder.type_path (LangItem::Kind::COPY); + + auto generics = setup_impl_generics (name, type_generics, + builder.trait_bound (copy_bound)); + + return builder.trait_impl (copy_trait_path, std::move (generics.self_type), + {}, std::move (generics.impl)); } void DeriveCopy::visit_struct (StructStruct &item) { - expanded = copy_impl (item.get_struct_name ().as_string ()); + expanded = copy_impl (item.get_struct_name ().as_string (), + item.get_generic_params ()); } void DeriveCopy::visit_tuple (TupleStruct &item) { - expanded = copy_impl (item.get_struct_name ().as_string ()); + expanded = copy_impl (item.get_struct_name ().as_string (), + item.get_generic_params ()); } void DeriveCopy::visit_enum (Enum &item) { - expanded = copy_impl (item.get_identifier ().as_string ()); + expanded = copy_impl (item.get_identifier ().as_string (), + item.get_generic_params ()); } void DeriveCopy::visit_union (Union &item) { - expanded = copy_impl (item.get_identifier ().as_string ()); + expanded = copy_impl (item.get_identifier ().as_string (), + item.get_generic_params ()); } } // namespace AST diff --git a/gcc/rust/expand/rust-derive-copy.h b/gcc/rust/expand/rust-derive-copy.h index 98decc0..71972eb 100644 --- a/gcc/rust/expand/rust-derive-copy.h +++ b/gcc/rust/expand/rust-derive-copy.h @@ -40,7 +40,9 @@ private: * * impl Copy for <type> {} */ - std::unique_ptr<Item> copy_impl (std::string name); + std::unique_ptr<Item> + copy_impl (std::string name, + const std::vector<std::unique_ptr<GenericParam>> &type_generics); virtual void visit_struct (StructStruct &item); virtual void visit_tuple (TupleStruct &item); diff --git a/gcc/rust/expand/rust-derive-debug.cc b/gcc/rust/expand/rust-derive-debug.cc new file mode 100644 index 0000000..a0bf9d8 --- /dev/null +++ b/gcc/rust/expand/rust-derive-debug.cc @@ -0,0 +1,121 @@ +// Copyright (C) 2025 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-derive-debug.h" +#include "rust-ast.h" +#include "rust-hir-map.h" +#include "rust-system.h" + +namespace Rust { +namespace AST { + +DeriveDebug::DeriveDebug (location_t loc) + : DeriveVisitor (loc), expanded (nullptr) +{} + +std::unique_ptr<Item> +DeriveDebug::go (Item &item) +{ + item.accept_vis (*this); + + rust_assert (expanded); + + return std::move (expanded); +} + +std::unique_ptr<AssociatedItem> +DeriveDebug::stub_debug_fn () +{ + auto unit_expr = builder.tuple (); + auto ok_expr + = ptrify (builder.path_in_expression (LangItem::Kind::RESULT_OK)); + + auto stub_return = builder.call (std::move (ok_expr), std::move (unit_expr)); + + // we can't use builder.block() here as it returns a unique_ptr<Expr> and + // Function's constructor expects a unique_ptr<BlockExpr> + auto block = std::unique_ptr<BlockExpr> ( + new BlockExpr ({}, std::move (stub_return), {}, {}, tl::nullopt, loc, loc)); + + auto self = builder.self_ref_param (); + + auto return_type + = ptrify (builder.type_path ({"core", "fmt", "Result"}, true)); + + auto mut_fmt_type_inner + = ptrify (builder.type_path ({"core", "fmt", "Formatter"}, true)); + + auto mut_fmt_type + = builder.reference_type (std::move (mut_fmt_type_inner), true); + + auto fmt = builder.function_param (builder.identifier_pattern ("_fmt"), + std::move (mut_fmt_type)); + + auto params = vec (std::move (self), std::move (fmt)); + + auto function = builder.function ("fmt", std::move (params), + std::move (return_type), std::move (block)); + + return function; +} + +std::unique_ptr<Item> +DeriveDebug::stub_derive_impl ( + std::string name, + const std::vector<std::unique_ptr<GenericParam>> &type_generics) +{ + auto trait_items = vec (stub_debug_fn ()); + + auto debug = builder.type_path ({"core", "fmt", "Debug"}, true); + auto generics + = setup_impl_generics (name, type_generics, builder.trait_bound (debug)); + + return builder.trait_impl (debug, std::move (generics.self_type), + std::move (trait_items), + std::move (generics.impl)); +} + +void +DeriveDebug::visit_struct (StructStruct &struct_item) +{ + expanded = stub_derive_impl (struct_item.get_identifier ().as_string (), + struct_item.get_generic_params ()); +} + +void +DeriveDebug::visit_tuple (TupleStruct &tuple_item) +{ + expanded = stub_derive_impl (tuple_item.get_identifier ().as_string (), + tuple_item.get_generic_params ()); +} + +void +DeriveDebug::visit_enum (Enum &enum_item) +{ + expanded = stub_derive_impl (enum_item.get_identifier ().as_string (), + enum_item.get_generic_params ()); +} + +void +DeriveDebug::visit_union (Union &enum_item) +{ + rust_error_at (loc, "derive(Debug) cannot be derived for unions"); +} + +} // namespace AST +} // namespace Rust diff --git a/gcc/rust/expand/rust-derive-debug.h b/gcc/rust/expand/rust-derive-debug.h new file mode 100644 index 0000000..14af89e --- /dev/null +++ b/gcc/rust/expand/rust-derive-debug.h @@ -0,0 +1,55 @@ +// Copyright (C) 2025 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_DERIVE_DEBUG_H +#define RUST_DERIVE_DEBUG_H + +#include "rust-derive.h" +#include "rust-ast.h" + +namespace Rust { +namespace AST { + +// This derive is currently incomplete and only generate a stub implementation +// which does not do any debug formatting +class DeriveDebug : DeriveVisitor +{ +public: + DeriveDebug (location_t loc); + + std::unique_ptr<Item> go (Item &); + +private: + std::unique_ptr<Item> expanded; + + std::unique_ptr<AssociatedItem> stub_debug_fn (); + + std::unique_ptr<Item> stub_derive_impl ( + std::string name, + const std::vector<std::unique_ptr<GenericParam>> &type_generics); + + virtual void visit_struct (StructStruct &struct_item) override; + virtual void visit_tuple (TupleStruct &tuple_item) override; + virtual void visit_enum (Enum &enum_item) override; + virtual void visit_union (Union &enum_item) override; +}; + +} // namespace AST +} // namespace Rust + +#endif // ! RUST_DERIVE_DEBUG_H diff --git a/gcc/rust/expand/rust-derive-default.cc b/gcc/rust/expand/rust-derive-default.cc new file mode 100644 index 0000000..2e8b456 --- /dev/null +++ b/gcc/rust/expand/rust-derive-default.cc @@ -0,0 +1,172 @@ +// Copyright (C) 2025 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-derive-default.h" +#include "rust-ast.h" +#include "rust-diagnostics.h" +#include "rust-path.h" +#include "rust-system.h" + +namespace Rust { +namespace AST { + +DeriveDefault::DeriveDefault (location_t loc) + : DeriveVisitor (loc), expanded (nullptr) +{} + +std::unique_ptr<Item> +DeriveDefault::go (Item &item) +{ + item.accept_vis (*this); + + rust_assert (expanded); + + return std::move (expanded); +} + +std::unique_ptr<Expr> +DeriveDefault::default_call (std::unique_ptr<Type> &&type) +{ + auto default_trait = builder.type_path ({"core", "default", "Default"}, true); + + auto default_fn + = builder.qualified_path_in_expression (std::move (type), default_trait, + builder.path_segment ("default")); + + return builder.call (std::move (default_fn)); +} + +std::unique_ptr<AssociatedItem> +DeriveDefault::default_fn (std::unique_ptr<Expr> &&return_expr) +{ + auto self_ty + = std::unique_ptr<Type> (new TypePath (builder.type_path ("Self"))); + + auto block = std::unique_ptr<BlockExpr> ( + new BlockExpr ({}, std::move (return_expr), {}, {}, tl::nullopt, loc, loc)); + + return builder.function ("default", {}, std::move (self_ty), + std::move (block)); +} + +std::unique_ptr<Item> +DeriveDefault::default_impl ( + std::unique_ptr<AssociatedItem> &&default_fn, std::string name, + const std::vector<std::unique_ptr<GenericParam>> &type_generics) +{ + auto default_path = builder.type_path ({"core", "default", "Default"}, true); + + auto trait_items = vec (std::move (default_fn)); + + auto generics = setup_impl_generics (name, type_generics, + builder.trait_bound (default_path)); + + return builder.trait_impl (default_path, std::move (generics.self_type), + std::move (trait_items), + std::move (generics.impl)); +} + +void +DeriveDefault::visit_struct (StructStruct &item) +{ + if (item.is_unit_struct ()) + { + auto unit_ctor + = builder.struct_expr_struct (item.get_struct_name ().as_string ()); + expanded = default_impl (default_fn (std::move (unit_ctor)), + item.get_struct_name ().as_string (), + item.get_generic_params ()); + return; + } + + auto cloned_fields = std::vector<std::unique_ptr<StructExprField>> (); + for (auto &field : item.get_fields ()) + { + auto name = field.get_field_name ().as_string (); + auto expr = default_call (field.get_field_type ().clone_type ()); + + cloned_fields.emplace_back ( + builder.struct_expr_field (std::move (name), std::move (expr))); + } + + auto ctor = builder.struct_expr (item.get_struct_name ().as_string (), + std::move (cloned_fields)); + + expanded = default_impl (default_fn (std::move (ctor)), + item.get_struct_name ().as_string (), + item.get_generic_params ()); +} + +void +DeriveDefault::visit_tuple (TupleStruct &tuple_item) +{ + auto defaulted_fields = std::vector<std::unique_ptr<Expr>> (); + + for (auto &field : tuple_item.get_fields ()) + { + auto type = field.get_field_type ().clone_type (); + + defaulted_fields.emplace_back (default_call (std::move (type))); + } + + auto return_expr + = builder.call (builder.identifier ( + tuple_item.get_struct_name ().as_string ()), + std::move (defaulted_fields)); + + expanded = default_impl (default_fn (std::move (return_expr)), + tuple_item.get_struct_name ().as_string (), + tuple_item.get_generic_params ()); +} + +void +DeriveDefault::visit_enum (Enum &enum_item) +{ + // This is no longer the case in later Rust versions where you can choose a + // default variant to emit using the `#[default]` attribute: + // + // ```rust + // #[derive(Default)] + // enum Baz { + // #[default] + // A, + // B(i32), + // C { a: i32 } + // } + // ``` + // + // will emit the following impl + // + // ```rust + // impl ::core::default::Default for Baz { + // #[inline] + // fn default() -> Baz { Self::A } + // } + // ``` + rust_error_at (loc, ErrorCode::E0665, + "%<Default%> cannot be derived for enums, only structs"); +} + +void +DeriveDefault::visit_union (Union &enum_item) +{ + rust_error_at (loc, "derive(Default) cannot be used on unions"); +} + +} // namespace AST +} // namespace Rust diff --git a/gcc/rust/expand/rust-derive-default.h b/gcc/rust/expand/rust-derive-default.h new file mode 100644 index 0000000..eae9e85 --- /dev/null +++ b/gcc/rust/expand/rust-derive-default.h @@ -0,0 +1,58 @@ +// Copyright (C) 2025 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_DERIVE_DEFAULT_H +#define RUST_DERIVE_DEFAULT_H + +#include "rust-derive.h" +#include "rust-ast.h" + +namespace Rust { +namespace AST { + +// This derive is currently incomplete and only generate a stub implementation +// which does not do any debug formatting +class DeriveDefault : DeriveVisitor +{ +public: + DeriveDefault (location_t loc); + + std::unique_ptr<Item> go (Item &); + +private: + std::unique_ptr<Item> expanded; + + std::unique_ptr<Expr> default_call (std::unique_ptr<Type> &&type); + + std::unique_ptr<AssociatedItem> + default_fn (std::unique_ptr<Expr> &&return_expr); + + std::unique_ptr<Item> default_impl ( + std::unique_ptr<AssociatedItem> &&default_fn, std::string name, + const std::vector<std::unique_ptr<GenericParam>> &type_generics); + + virtual void visit_struct (StructStruct &struct_item) override; + virtual void visit_tuple (TupleStruct &tuple_item) override; + virtual void visit_enum (Enum &enum_item) override; + virtual void visit_union (Union &enum_item) override; +}; + +} // namespace AST +} // namespace Rust + +#endif // ! RUST_DERIVE_DEFAULT_H diff --git a/gcc/rust/expand/rust-derive-eq.cc b/gcc/rust/expand/rust-derive-eq.cc new file mode 100644 index 0000000..5e7a894 --- /dev/null +++ b/gcc/rust/expand/rust-derive-eq.cc @@ -0,0 +1,216 @@ +// Copyright (C) 2025 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-derive-eq.h" +#include "rust-ast.h" +#include "rust-expr.h" +#include "rust-item.h" +#include "rust-path.h" +#include "rust-pattern.h" +#include "rust-system.h" + +namespace Rust { +namespace AST { + +DeriveEq::DeriveEq (location_t loc) : DeriveVisitor (loc) {} + +std::vector<std::unique_ptr<AST::Item>> +DeriveEq::go (Item &item) +{ + item.accept_vis (*this); + + return std::move (expanded); +} + +std::unique_ptr<AssociatedItem> +DeriveEq::assert_receiver_is_total_eq_fn ( + std::vector<std::unique_ptr<Type>> &&types) +{ + auto stmts = std::vector<std::unique_ptr<Stmt>> (); + + stmts.emplace_back (assert_param_is_eq ()); + + for (auto &&type : types) + stmts.emplace_back (assert_type_is_eq (std::move (type))); + + auto block = std::unique_ptr<BlockExpr> ( + new BlockExpr (std::move (stmts), nullptr, {}, {}, tl::nullopt, loc, loc)); + + auto self = builder.self_ref_param (); + + return builder.function ("assert_receiver_is_total_eq", + vec (std::move (self)), {}, std::move (block)); +} + +std::unique_ptr<Stmt> +DeriveEq::assert_param_is_eq () +{ + auto eq_bound = std::unique_ptr<TypeParamBound> ( + new TraitBound (builder.type_path ({"core", "cmp", "Eq"}, true), loc)); + + auto sized_bound = std::unique_ptr<TypeParamBound> ( + new TraitBound (builder.type_path (LangItem::Kind::SIZED), loc, false, + true /* opening_question_mark */)); + + auto bounds = vec (std::move (eq_bound), std::move (sized_bound)); + + auto assert_param_is_eq = "AssertParamIsEq"; + + auto t = std::unique_ptr<GenericParam> ( + new TypeParam (Identifier ("T"), loc, std::move (bounds))); + + return builder.struct_struct ( + assert_param_is_eq, vec (std::move (t)), + {StructField ( + Identifier ("_t"), + builder.single_generic_type_path ( + LangItem::Kind::PHANTOM_DATA, + GenericArgs ( + {}, {GenericArg::create_type (builder.single_type_path ("T"))}, {})), + Visibility::create_private (), loc)}); +} + +std::unique_ptr<Stmt> +DeriveEq::assert_type_is_eq (std::unique_ptr<Type> &&type) +{ + auto assert_param_is_eq = "AssertParamIsEq"; + + // AssertParamIsCopy::<Self> + auto assert_param_is_eq_ty + = std::unique_ptr<TypePathSegment> (new TypePathSegmentGeneric ( + PathIdentSegment (assert_param_is_eq, loc), false, + GenericArgs ({}, {GenericArg::create_type (std::move (type))}, {}, loc), + loc)); + + // TODO: Improve this, it's really ugly + auto type_paths = std::vector<std::unique_ptr<TypePathSegment>> (); + type_paths.emplace_back (std::move (assert_param_is_eq_ty)); + + auto full_path + = std::unique_ptr<Type> (new TypePath ({std::move (type_paths)}, loc)); + + return builder.let (builder.wildcard (), std::move (full_path)); +} + +std::vector<std::unique_ptr<Item>> +DeriveEq::eq_impls ( + std::unique_ptr<AssociatedItem> &&fn, std::string name, + const std::vector<std::unique_ptr<GenericParam>> &type_generics) +{ + // We create two copies of the type-path to avoid duplicate NodeIds + auto eq = builder.type_path ({"core", "cmp", "Eq"}, true); + auto eq_bound + = builder.trait_bound (builder.type_path ({"core", "cmp", "Eq"}, true)); + + auto steq = builder.type_path (LangItem::Kind::STRUCTURAL_TEQ); + + auto trait_items = vec (std::move (fn)); + + auto eq_generics + = setup_impl_generics (name, type_generics, std::move (eq_bound)); + auto steq_generics = setup_impl_generics (name, type_generics); + + auto eq_impl = builder.trait_impl (eq, std::move (eq_generics.self_type), + std::move (trait_items), + std::move (eq_generics.impl)); + auto steq_impl + = builder.trait_impl (steq, std::move (steq_generics.self_type), + std::move (trait_items), + std::move (steq_generics.impl)); + + return vec (std::move (eq_impl), std::move (steq_impl)); +} + +void +DeriveEq::visit_tuple (TupleStruct &item) +{ + auto types = std::vector<std::unique_ptr<Type>> (); + + for (auto &field : item.get_fields ()) + types.emplace_back (field.get_field_type ().clone_type ()); + + expanded = eq_impls (assert_receiver_is_total_eq_fn (std::move (types)), + item.get_identifier ().as_string (), + item.get_generic_params ()); +} + +void +DeriveEq::visit_struct (StructStruct &item) +{ + auto types = std::vector<std::unique_ptr<Type>> (); + + for (auto &field : item.get_fields ()) + types.emplace_back (field.get_field_type ().clone_type ()); + + expanded = eq_impls (assert_receiver_is_total_eq_fn (std::move (types)), + item.get_identifier ().as_string (), + item.get_generic_params ()); +} + +void +DeriveEq::visit_enum (Enum &item) +{ + auto types = std::vector<std::unique_ptr<Type>> (); + + for (auto &variant : item.get_variants ()) + { + switch (variant->get_enum_item_kind ()) + { + case EnumItem::Kind::Identifier: + case EnumItem::Kind::Discriminant: + // nothing to do as they contain no inner types + continue; + case EnumItem::Kind::Tuple: { + auto &tuple = static_cast<EnumItemTuple &> (*variant); + + for (auto &field : tuple.get_tuple_fields ()) + types.emplace_back (field.get_field_type ().clone_type ()); + + break; + } + case EnumItem::Kind::Struct: { + auto &tuple = static_cast<EnumItemStruct &> (*variant); + + for (auto &field : tuple.get_struct_fields ()) + types.emplace_back (field.get_field_type ().clone_type ()); + + break; + } + } + } + + expanded = eq_impls (assert_receiver_is_total_eq_fn (std::move (types)), + item.get_identifier ().as_string (), + item.get_generic_params ()); +} + +void +DeriveEq::visit_union (Union &item) +{ + auto types = std::vector<std::unique_ptr<Type>> (); + + for (auto &field : item.get_variants ()) + types.emplace_back (field.get_field_type ().clone_type ()); + + expanded = eq_impls (assert_receiver_is_total_eq_fn (std::move (types)), + item.get_identifier ().as_string (), + item.get_generic_params ()); +} + +} // namespace AST +} // namespace Rust diff --git a/gcc/rust/expand/rust-derive-eq.h b/gcc/rust/expand/rust-derive-eq.h new file mode 100644 index 0000000..17af526 --- /dev/null +++ b/gcc/rust/expand/rust-derive-eq.h @@ -0,0 +1,82 @@ +// Copyright (C) 2025 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_DERIVE_EQ_H +#define RUST_DERIVE_EQ_H + +#include "rust-derive.h" + +namespace Rust { +namespace AST { + +// FIXME: Need to figure out structuraleq marker trait + +class DeriveEq : DeriveVisitor +{ +public: + DeriveEq (location_t loc); + + std::vector<std::unique_ptr<AST::Item>> go (Item &item); + +private: + std::vector<std::unique_ptr<Item>> expanded; + + /** + * Create the actual `assert_receiver_is_total_eq` function of the + * implementation, which asserts that every type contained within our targeted + * type also implements `Eq`. + */ + std::unique_ptr<AssociatedItem> + assert_receiver_is_total_eq_fn (std::vector<std::unique_ptr<Type>> &&types); + + /** + * Create the Eq trait implementation for a type + * + * impl Eq for <type> { + * <assert_receiver_is_total_eq> + * } + * + */ + std::vector<std::unique_ptr<Item>> + eq_impls (std::unique_ptr<AssociatedItem> &&fn, std::string name, + const std::vector<std::unique_ptr<GenericParam>> &type_generics); + + /** + * Generate the following structure definition + * + * struct AssertParamIsEq<T: Eq + ?Sized> { _t: PhantomData<T> } + */ + std::unique_ptr<Stmt> assert_param_is_eq (); + + /** + * Generate a let statement to assert a type implements `Eq` + * + * let _: AssertParamIsEq<type>; + */ + std::unique_ptr<Stmt> assert_type_is_eq (std::unique_ptr<Type> &&type); + + virtual void visit_struct (StructStruct &item); + virtual void visit_tuple (TupleStruct &item); + virtual void visit_enum (Enum &item); + virtual void visit_union (Union &item); +}; + +} // namespace AST +} // namespace Rust + +#endif // ! RUST_DERIVE_EQ_H diff --git a/gcc/rust/expand/rust-derive-hash.cc b/gcc/rust/expand/rust-derive-hash.cc new file mode 100644 index 0000000..0c9b0f7 --- /dev/null +++ b/gcc/rust/expand/rust-derive-hash.cc @@ -0,0 +1,293 @@ +// Copyright (C) 2025 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-derive-hash.h" +#include "rust-ast.h" +#include "rust-expr.h" +#include "rust-item.h" +#include "rust-path.h" +#include "rust-pattern.h" +#include "rust-stmt.h" +#include "rust-system.h" + +namespace Rust { +namespace AST { + +DeriveHash::DeriveHash (location_t loc) : DeriveVisitor (loc) {} + +std::unique_ptr<AST::Item> +DeriveHash::go (Item &item) +{ + item.accept_vis (*this); + + return std::move (expanded); +} + +std::unique_ptr<Expr> +DeriveHash::hash_call (std::unique_ptr<Expr> &&value) +{ + auto hash + = builder.path_in_expression ({"core", "hash", "Hash", "hash"}, true); + + return builder.call (ptrify (hash), + vec (std::move (value), + builder.identifier (DeriveHash::state))); +} + +std::unique_ptr<AssociatedItem> +DeriveHash::hash_fn (std::unique_ptr<BlockExpr> &&block) +{ + auto hash_calls = std::vector<std::unique_ptr<Stmt>> (); + + auto state_type = std::unique_ptr<TypeNoBounds> ( + new TypePath (builder.type_path (DeriveHash::state_type))); + auto state_param = + + builder.function_param (builder.identifier_pattern (DeriveHash::state), + builder.reference_type (std::move (state_type), + true)); + + auto params = vec (builder.self_ref_param (), std::move (state_param)); + auto bounds = vec ( + builder.trait_bound (builder.type_path ({"core", "hash", "Hasher"}, true))); + auto generics = vec ( + builder.generic_type_param (DeriveHash::state_type, std::move (bounds))); + + return builder.function ("hash", std::move (params), nullptr, + std::move (block), std::move (generics)); +} + +std::unique_ptr<Item> +DeriveHash::hash_impl ( + std::unique_ptr<AssociatedItem> &&hash_fn, std::string name, + const std::vector<std::unique_ptr<GenericParam>> &type_generics) +{ + auto hash_path = builder.type_path ({"core", "hash", "Hash"}, true); + + auto trait_items = vec (std::move (hash_fn)); + + auto generics = setup_impl_generics (name, type_generics, + builder.trait_bound (hash_path)); + + return builder.trait_impl (hash_path, std::move (generics.self_type), + std::move (trait_items), + std::move (generics.impl)); +} + +void +DeriveHash::visit_struct (StructStruct &item) +{ + auto hash_calls = std::vector<std::unique_ptr<Stmt>> (); + + for (auto &field : item.get_fields ()) + { + auto value = builder.ref ( + builder.field_access (builder.identifier ("self"), + field.get_field_name ().as_string ())); + + auto stmt = builder.statementify (hash_call (std::move (value))); + + hash_calls.emplace_back (std::move (stmt)); + } + + auto block = builder.block (std::move (hash_calls)); + + expanded = hash_impl (hash_fn (std::move (block)), + item.get_identifier ().as_string (), + item.get_generic_params ()); +} + +void +DeriveHash::visit_tuple (TupleStruct &item) +{ + auto hash_calls = std::vector<std::unique_ptr<Stmt>> (); + + for (size_t idx = 0; idx < item.get_fields ().size (); idx++) + { + auto value = builder.ref (builder.tuple_idx ("self", idx)); + + auto stmt = builder.statementify (hash_call (std::move (value))); + + hash_calls.emplace_back (std::move (stmt)); + } + + auto block = builder.block (std::move (hash_calls)); + + expanded = hash_impl (hash_fn (std::move (block)), + item.get_identifier ().as_string (), + item.get_generic_params ()); +} + +MatchCase +DeriveHash::match_enum_tuple (PathInExpression variant_path, + const EnumItemTuple &variant) +{ + auto self_patterns = std::vector<std::unique_ptr<Pattern>> (); + auto hash_calls = std::vector<std::unique_ptr<Stmt>> (); + + for (size_t i = 0; i < variant.get_tuple_fields ().size (); i++) + { + auto pattern = "__self_" + std::to_string (i); + + auto call = hash_call (builder.ref (builder.identifier (pattern))); + + self_patterns.emplace_back (builder.identifier_pattern (pattern)); + hash_calls.emplace_back (builder.statementify (std::move (call))); + } + + auto patterns_elts = std::unique_ptr<TupleStructItems> ( + new TupleStructItemsNoRange (std::move (self_patterns))); + auto pattern = std::unique_ptr<Pattern> ( + new ReferencePattern (std::unique_ptr<Pattern> (new TupleStructPattern ( + variant_path, std::move (patterns_elts))), + false, false, loc)); + + auto block = builder.block (std::move (hash_calls)); + + return builder.match_case (std::move (pattern), std::move (block)); +} + +MatchCase +DeriveHash::match_enum_struct (PathInExpression variant_path, + const EnumItemStruct &variant) +{ + auto field_patterns = std::vector<std::unique_ptr<StructPatternField>> (); + auto hash_calls = std::vector<std::unique_ptr<Stmt>> (); + + for (const auto &field : variant.get_struct_fields ()) + { + auto call = hash_call (builder.ref ( + builder.identifier (field.get_field_name ().as_string ()))); + + field_patterns.emplace_back ( + std::unique_ptr<StructPatternField> (new StructPatternFieldIdent ( + field.get_field_name (), false /* is_ref? true? */, false, {}, loc))); + + hash_calls.emplace_back (builder.statementify (std::move (call))); + } + + auto pattern_elts = StructPatternElements (std::move (field_patterns)); + auto pattern = std::unique_ptr<Pattern> ( + new ReferencePattern (std::unique_ptr<Pattern> (new StructPattern ( + variant_path, loc, pattern_elts)), + false, false, loc)); + + auto block = builder.block (std::move (hash_calls)); + return builder.match_case (std::move (pattern), std::move (block)); +} + +void +DeriveHash::visit_enum (Enum &item) +{ + // Enums are a bit different: We start by hashing the discriminant value of + // the enum instance, and then hash all of the data contained in each of the + // enum's variants. For data-less variants, we don't have any data to hash, so + // hashing the discriminant value is enough. To access the rest of the + // variants' data, we create a match and destructure each internal field and + // hash it. + // + // So for example with the following enum: + // + // ```rust + // enum Foo { + // A, + // B(i32), + // C { a: i32 }, + // } + // ``` + // + // we create the following implementation: + // + // ```rust + // fn hash<H: Hasher>(&self, state: &mut H) { + // let discriminant = intrinsics::discriminant_value(&self); + // Hash::hash(&discriminant, state); + // + // match self { + // B(self_0) => { Hash::hash(self_0, state); }, + // C { a } => { Hash::hash(a, state); }, + // _ => {}, + // } + // } + // ``` + // + // Note the extra wildcard pattern to satisfy the exhaust checker. + + auto cases = std::vector<MatchCase> (); + auto type_name = item.get_identifier ().as_string (); + + auto intrinsic = ptrify ( + builder.path_in_expression ({"core", "intrinsics", "discriminant_value"}, + true)); + + auto let_discr + = builder.let (builder.identifier_pattern (DeriveHash::discr), nullptr, + builder.call (std::move (intrinsic), + builder.identifier ("self"))); + + auto discr_hash = builder.statementify ( + hash_call (builder.ref (builder.identifier (DeriveHash::discr)))); + + for (auto &variant : item.get_variants ()) + { + auto variant_path + = builder.variant_path (type_name, + variant->get_identifier ().as_string ()); + + switch (variant->get_enum_item_kind ()) + { + case EnumItem::Kind::Identifier: + case EnumItem::Kind::Discriminant: + // nothing to do in these cases, as we just need to hash the + // discriminant value + continue; + case EnumItem::Kind::Tuple: + cases.emplace_back ( + match_enum_tuple (variant_path, + static_cast<EnumItemTuple &> (*variant))); + break; + case EnumItem::Kind::Struct: + cases.emplace_back ( + match_enum_struct (variant_path, + static_cast<EnumItemStruct &> (*variant))); + break; + } + } + + // The extra empty wildcard case + cases.emplace_back ( + builder.match_case (builder.wildcard (), builder.block ())); + + auto match = builder.match (builder.identifier ("self"), std::move (cases)); + + auto block + = builder.block (vec (std::move (let_discr), std::move (discr_hash)), + std::move (match)); + + expanded = hash_impl (hash_fn (std::move (block)), type_name, + item.get_generic_params ()); +} + +void +DeriveHash::visit_union (Union &item) +{ + rust_error_at (item.get_locus (), "derive(Hash) cannot be used on unions"); +} + +} // namespace AST +} // namespace Rust diff --git a/gcc/rust/expand/rust-derive-hash.h b/gcc/rust/expand/rust-derive-hash.h new file mode 100644 index 0000000..02b0bee --- /dev/null +++ b/gcc/rust/expand/rust-derive-hash.h @@ -0,0 +1,61 @@ +// Copyright (C) 2025 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_DERIVE_HASH_H +#define RUST_DERIVE_HASH_H + +#include "rust-derive.h" + +namespace Rust { +namespace AST { + +class DeriveHash : DeriveVisitor +{ +public: + DeriveHash (location_t loc); + + std::unique_ptr<AST::Item> go (Item &item); + +private: + std::unique_ptr<Item> expanded; + + constexpr static const char *state = "#state"; + constexpr static const char *state_type = "#__H"; + constexpr static const char *discr = "#discr"; + + std::unique_ptr<Expr> hash_call (std::unique_ptr<Expr> &&value); + std::unique_ptr<AssociatedItem> hash_fn (std::unique_ptr<BlockExpr> &&block); + std::unique_ptr<Item> + hash_impl (std::unique_ptr<AssociatedItem> &&hash_fn, std::string name, + const std::vector<std::unique_ptr<GenericParam>> &type_generics); + + MatchCase match_enum_tuple (PathInExpression variant_path, + const EnumItemTuple &variant); + MatchCase match_enum_struct (PathInExpression variant_path, + const EnumItemStruct &variant); + + virtual void visit_struct (StructStruct &item); + virtual void visit_tuple (TupleStruct &item); + virtual void visit_enum (Enum &item); + virtual void visit_union (Union &item); +}; + +} // namespace AST +} // namespace Rust + +#endif // ! RUST_DERIVE_HASH_H diff --git a/gcc/rust/expand/rust-derive-partial-eq.cc b/gcc/rust/expand/rust-derive-partial-eq.cc new file mode 100644 index 0000000..ff66faa --- /dev/null +++ b/gcc/rust/expand/rust-derive-partial-eq.cc @@ -0,0 +1,313 @@ +// Copyright (C) 2025 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-derive-partial-eq.h" +#include "rust-ast.h" +#include "rust-expr.h" +#include "rust-item.h" +#include "rust-operators.h" +#include "rust-path.h" +#include "rust-pattern.h" +#include "rust-system.h" + +namespace Rust { +namespace AST { +DerivePartialEq::DerivePartialEq (location_t loc) : DeriveVisitor (loc) {} + +std::vector<std::unique_ptr<AST::Item>> +DerivePartialEq::go (Item &item) +{ + item.accept_vis (*this); + + return std::move (expanded); +} + +std::vector<std::unique_ptr<Item>> +DerivePartialEq::partialeq_impls ( + std::unique_ptr<AssociatedItem> &&eq_fn, std::string name, + const std::vector<std::unique_ptr<GenericParam>> &type_generics) +{ + auto eq = builder.type_path (LangItem::Kind::EQ); + auto speq = builder.type_path (LangItem::Kind::STRUCTURAL_PEQ); + + auto trait_items = vec (std::move (eq_fn)); + + // no extra bound on StructuralPeq + auto peq_generics + = setup_impl_generics (name, type_generics, builder.trait_bound (eq)); + auto speq_generics = setup_impl_generics (name, type_generics); + + auto peq = builder.trait_impl (eq, std::move (peq_generics.self_type), + std::move (trait_items), + std::move (peq_generics.impl)); + + auto structural_peq + = builder.trait_impl (speq, std::move (speq_generics.self_type), {}, + std::move (speq_generics.impl)); + + return vec (std::move (peq), std::move (structural_peq)); +} + +std::unique_ptr<AssociatedItem> +DerivePartialEq::eq_fn (std::unique_ptr<Expr> &&cmp_expression, + std::string type_name) +{ + auto block = builder.block (tl::nullopt, std::move (cmp_expression)); + + auto self_type + = std::unique_ptr<TypeNoBounds> (new TypePath (builder.type_path ("Self"))); + + auto params + = vec (builder.self_ref_param (), + builder.function_param (builder.identifier_pattern ("other"), + builder.reference_type ( + std::move (self_type)))); + + return builder.function ("eq", std::move (params), + builder.single_type_path ("bool"), + std::move (block)); +} + +DerivePartialEq::SelfOther +DerivePartialEq::tuple_indexes (int idx) +{ + return SelfOther{ + builder.tuple_idx ("self", idx), + builder.tuple_idx ("other", idx), + }; +} + +DerivePartialEq::SelfOther +DerivePartialEq::field_acccesses (const std::string &field_name) +{ + return SelfOther{ + builder.field_access (builder.identifier ("self"), field_name), + builder.field_access (builder.identifier ("other"), field_name), + }; +} + +std::unique_ptr<Expr> +DerivePartialEq::build_eq_expression ( + std::vector<SelfOther> &&field_expressions) +{ + // for unit structs or empty tuples, this is always true + if (field_expressions.empty ()) + return builder.literal_bool (true); + + auto cmp_expression + = builder.comparison_expr (std::move (field_expressions.at (0).self_expr), + std::move (field_expressions.at (0).other_expr), + ComparisonOperator::EQUAL); + + for (size_t i = 1; i < field_expressions.size (); i++) + { + auto tmp = builder.comparison_expr ( + std::move (field_expressions.at (i).self_expr), + std::move (field_expressions.at (i).other_expr), + ComparisonOperator::EQUAL); + + cmp_expression + = builder.boolean_operation (std::move (cmp_expression), + std::move (tmp), + LazyBooleanOperator::LOGICAL_AND); + } + + return cmp_expression; +} + +void +DerivePartialEq::visit_tuple (TupleStruct &item) +{ + auto type_name = item.get_struct_name ().as_string (); + auto fields = std::vector<SelfOther> (); + + for (size_t idx = 0; idx < item.get_fields ().size (); idx++) + fields.emplace_back (tuple_indexes (idx)); + + auto fn = eq_fn (build_eq_expression (std::move (fields)), type_name); + + expanded + = partialeq_impls (std::move (fn), type_name, item.get_generic_params ()); +} + +void +DerivePartialEq::visit_struct (StructStruct &item) +{ + auto type_name = item.get_struct_name ().as_string (); + auto fields = std::vector<SelfOther> (); + + for (auto &field : item.get_fields ()) + fields.emplace_back ( + field_acccesses (field.get_field_name ().as_string ())); + + auto fn = eq_fn (build_eq_expression (std::move (fields)), type_name); + + expanded + = partialeq_impls (std::move (fn), type_name, item.get_generic_params ()); +} + +MatchCase +DerivePartialEq::match_enum_identifier ( + PathInExpression variant_path, const std::unique_ptr<EnumItem> &variant) +{ + auto inner_ref_patterns + = vec (builder.ref_pattern ( + std::unique_ptr<Pattern> (new PathInExpression (variant_path))), + builder.ref_pattern ( + std::unique_ptr<Pattern> (new PathInExpression (variant_path)))); + + auto tuple_items = std::make_unique<TuplePatternItemsMultiple> ( + std::move (inner_ref_patterns)); + + auto pattern = std::make_unique<TuplePattern> (std::move (tuple_items), loc); + + return builder.match_case (std::move (pattern), builder.literal_bool (true)); +} + +MatchCase +DerivePartialEq::match_enum_tuple (PathInExpression variant_path, + const EnumItemTuple &variant) +{ + auto self_patterns = std::vector<std::unique_ptr<Pattern>> (); + auto other_patterns = std::vector<std::unique_ptr<Pattern>> (); + + auto self_other_exprs = std::vector<SelfOther> (); + + for (size_t i = 0; i < variant.get_tuple_fields ().size (); i++) + { + // The patterns we're creating for each field are `self_<i>` and + // `other_<i>` where `i` is the index of the field. It doesn't actually + // matter what we use, as long as it's ordered, unique, and that we can + // reuse it in the match case's return expression to check that they are + // equal. + + auto self_pattern_str = "__self_" + std::to_string (i); + auto other_pattern_str = "__other_" + std::to_string (i); + + rust_debug ("]ARTHUR[ %s", self_pattern_str.c_str ()); + + self_patterns.emplace_back ( + builder.identifier_pattern (self_pattern_str)); + other_patterns.emplace_back ( + builder.identifier_pattern (other_pattern_str)); + + self_other_exprs.emplace_back (SelfOther{ + builder.identifier (self_pattern_str), + builder.identifier (other_pattern_str), + }); + } + + auto self_pattern_items = std::unique_ptr<TupleStructItems> ( + new TupleStructItemsNoRange (std::move (self_patterns))); + auto other_pattern_items = std::unique_ptr<TupleStructItems> ( + new TupleStructItemsNoRange (std::move (other_patterns))); + + auto self_pattern = std::unique_ptr<Pattern> ( + new ReferencePattern (std::unique_ptr<Pattern> (new TupleStructPattern ( + variant_path, std::move (self_pattern_items))), + false, false, loc)); + auto other_pattern = std::unique_ptr<Pattern> ( + new ReferencePattern (std::unique_ptr<Pattern> (new TupleStructPattern ( + variant_path, std::move (other_pattern_items))), + false, false, loc)); + + auto tuple_items = std::make_unique<TuplePatternItemsMultiple> ( + vec (std::move (self_pattern), std::move (other_pattern))); + + auto pattern = std::make_unique<TuplePattern> (std::move (tuple_items), loc); + + auto expr = build_eq_expression (std::move (self_other_exprs)); + + return builder.match_case (std::move (pattern), std::move (expr)); +} + +MatchCase +DerivePartialEq::match_enum_struct (PathInExpression variant_path, + const EnumItemStruct &variant) +{ + // NOTE: We currently do not support compiling struct patterns where an + // identifier is assigned a new pattern, e.g. Bloop { f0: x } + // This is what we should be using to compile PartialEq for enum struct + // variants, as we need to be comparing the field of each instance meaning we + // need to give two different names to two different instances of the same + // field. We cannot just use the field's name like we do when deriving + // `Clone`. + + rust_unreachable (); +} + +void +DerivePartialEq::visit_enum (Enum &item) +{ + auto cases = std::vector<MatchCase> (); + auto type_name = item.get_identifier ().as_string (); + + for (auto &variant : item.get_variants ()) + { + auto variant_path + = builder.variant_path (type_name, + variant->get_identifier ().as_string ()); + + switch (variant->get_enum_item_kind ()) + { + case EnumItem::Kind::Identifier: + case EnumItem::Kind::Discriminant: + cases.emplace_back (match_enum_identifier (variant_path, variant)); + break; + case EnumItem::Kind::Tuple: + cases.emplace_back ( + match_enum_tuple (variant_path, + static_cast<EnumItemTuple &> (*variant))); + break; + case EnumItem::Kind::Struct: + rust_sorry_at ( + item.get_locus (), + "cannot derive(PartialEq) for enum struct variants yet"); + break; + } + } + + // NOTE: Mention using discriminant_value and skipping that last case, and + // instead skipping all identifiers/discriminant enum items and returning + // `true` in the wildcard case + + // In case the two instances of `Self` don't have the same discriminant, + // automatically return false. + cases.emplace_back ( + builder.match_case (builder.wildcard (), builder.literal_bool (false))); + + auto match + = builder.match (builder.tuple (vec (builder.identifier ("self"), + builder.identifier ("other"))), + std::move (cases)); + + auto fn = eq_fn (std::move (match), type_name); + + expanded + = partialeq_impls (std::move (fn), type_name, item.get_generic_params ()); +} + +void +DerivePartialEq::visit_union (Union &item) +{ + rust_error_at (item.get_locus (), + "derive(PartialEq) cannot be used on unions"); +} + +} // namespace AST +} // namespace Rust diff --git a/gcc/rust/expand/rust-derive-partial-eq.h b/gcc/rust/expand/rust-derive-partial-eq.h new file mode 100644 index 0000000..ac963a6 --- /dev/null +++ b/gcc/rust/expand/rust-derive-partial-eq.h @@ -0,0 +1,85 @@ +// Copyright (C) 2025 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_DERIVE_PARTIAL_EQ_H +#define RUST_DERIVE_PARTIAL_EQ_H + +#include "rust-derive.h" +#include "rust-path.h" + +namespace Rust { +namespace AST { + +class DerivePartialEq : DeriveVisitor +{ +public: + DerivePartialEq (location_t loc); + + std::vector<std::unique_ptr<AST::Item>> go (Item &item); + +private: + std::vector<std::unique_ptr<Item>> expanded; + + /** + * Generate both an implementation of `PartialEq` and `StructuralPartialEq` + * for the given type + */ + std::vector<std::unique_ptr<Item>> partialeq_impls ( + std::unique_ptr<AssociatedItem> &&eq_fn, std::string name, + const std::vector<std::unique_ptr<GenericParam>> &type_generics); + + std::unique_ptr<AssociatedItem> eq_fn (std::unique_ptr<Expr> &&cmp_expression, + std::string type_name); + + /** + * A pair of two expressions from each instance being compared. E.g. this + * could be `self.0` and `other.0`, or `self.field` and `other.field` + */ + struct SelfOther + { + std::unique_ptr<Expr> self_expr; + std::unique_ptr<Expr> other_expr; + }; + + SelfOther tuple_indexes (int idx); + SelfOther field_acccesses (const std::string &field_name); + + /** + * Build a suite of equality arithmetic expressions chained together by a + * boolean AND operator + */ + std::unique_ptr<Expr> + build_eq_expression (std::vector<SelfOther> &&field_expressions); + + MatchCase match_enum_identifier (PathInExpression variant_path, + const std::unique_ptr<EnumItem> &variant); + MatchCase match_enum_tuple (PathInExpression variant_path, + const EnumItemTuple &variant); + MatchCase match_enum_struct (PathInExpression variant_path, + const EnumItemStruct &variant); + + virtual void visit_struct (StructStruct &item); + virtual void visit_tuple (TupleStruct &item); + virtual void visit_enum (Enum &item); + virtual void visit_union (Union &item); +}; + +} // namespace AST +} // namespace Rust + +#endif // ! RUST_DERIVE_PARTIAL_EQ_H diff --git a/gcc/rust/expand/rust-derive.cc b/gcc/rust/expand/rust-derive.cc index a378483..015b81e 100644 --- a/gcc/rust/expand/rust-derive.cc +++ b/gcc/rust/expand/rust-derive.cc @@ -19,6 +19,11 @@ #include "rust-derive.h" #include "rust-derive-clone.h" #include "rust-derive-copy.h" +#include "rust-derive-debug.h" +#include "rust-derive-default.h" +#include "rust-derive-eq.h" +#include "rust-derive-partial-eq.h" +#include "rust-derive-hash.h" namespace Rust { namespace AST { @@ -27,28 +32,113 @@ DeriveVisitor::DeriveVisitor (location_t loc) : loc (loc), builder (Builder (loc)) {} -std::unique_ptr<Item> +std::vector<std::unique_ptr<Item>> DeriveVisitor::derive (Item &item, const Attribute &attr, BuiltinMacro to_derive) { + auto loc = attr.get_locus (); + switch (to_derive) { case BuiltinMacro::Clone: - return DeriveClone (attr.get_locus ()).go (item); + return vec (DeriveClone (loc).go (item)); case BuiltinMacro::Copy: - return DeriveCopy (attr.get_locus ()).go (item); + return vec (DeriveCopy (loc).go (item)); case BuiltinMacro::Debug: + rust_warning_at ( + loc, 0, + "derive(Debug) is not fully implemented yet and has no effect - only a " + "stub implementation will be generated"); + return vec (DeriveDebug (loc).go (item)); case BuiltinMacro::Default: + return vec (DeriveDefault (loc).go (item)); case BuiltinMacro::Eq: + return DeriveEq (loc).go (item); case BuiltinMacro::PartialEq: + return DerivePartialEq (loc).go (item); + case BuiltinMacro::Hash: + return vec (DeriveHash (loc).go (item)); case BuiltinMacro::Ord: case BuiltinMacro::PartialOrd: - case BuiltinMacro::Hash: default: - rust_sorry_at (attr.get_locus (), "unimplemented builtin derive macro"); - return nullptr; + rust_sorry_at (loc, "unimplemented builtin derive macro"); + return {}; }; } +DeriveVisitor::ImplGenerics +DeriveVisitor::setup_impl_generics ( + const std::string &type_name, + const std::vector<std::unique_ptr<GenericParam>> &type_generics, + tl::optional<std::unique_ptr<TypeParamBound>> &&extra_bound) const +{ + std::vector<Lifetime> lifetime_args; + std::vector<GenericArg> generic_args; + std::vector<std::unique_ptr<GenericParam>> impl_generics; + for (const auto &generic : type_generics) + { + switch (generic->get_kind ()) + { + case GenericParam::Kind::Lifetime: { + LifetimeParam &lifetime_param = (LifetimeParam &) *generic.get (); + + Lifetime l = builder.new_lifetime (lifetime_param.get_lifetime ()); + lifetime_args.push_back (std::move (l)); + + auto impl_lifetime_param + = builder.new_lifetime_param (lifetime_param); + impl_generics.push_back (std::move (impl_lifetime_param)); + } + break; + + case GenericParam::Kind::Type: { + TypeParam &type_param = (TypeParam &) *generic.get (); + + std::unique_ptr<Type> associated_type = builder.single_type_path ( + type_param.get_type_representation ().as_string ()); + + GenericArg type_arg + = GenericArg::create_type (std::move (associated_type)); + generic_args.push_back (std::move (type_arg)); + + std::vector<std::unique_ptr<TypeParamBound>> extra_bounds; + + if (extra_bound) + extra_bounds.emplace_back (std::move (*extra_bound)); + + auto impl_type_param + = builder.new_type_param (type_param, std::move (extra_bounds)); + + impl_generics.push_back (std::move (impl_type_param)); + } + break; + + case GenericParam::Kind::Const: { + rust_unreachable (); + + // TODO + // const ConstGenericParam *const_param + // = (const ConstGenericParam *) generic.get (); + // std::unique_ptr<Expr> const_expr = nullptr; + + // GenericArg type_arg + // = GenericArg::create_const (std::move (const_expr)); + // generic_args.push_back (std::move (type_arg)); + } + break; + } + } + + auto generic_args_for_self + = GenericArgs (lifetime_args, generic_args, {} /*binding args*/, loc); + + std::unique_ptr<Type> self_type_path + = impl_generics.empty () + ? builder.single_type_path (type_name) + : builder.single_generic_type_path (type_name, generic_args_for_self); + + return ImplGenerics{std::move (self_type_path), std::move (impl_generics)}; +} + } // namespace AST } // namespace Rust diff --git a/gcc/rust/expand/rust-derive.h b/gcc/rust/expand/rust-derive.h index 1924432..5fca49c 100644 --- a/gcc/rust/expand/rust-derive.h +++ b/gcc/rust/expand/rust-derive.h @@ -34,8 +34,12 @@ namespace AST { class DeriveVisitor : public AST::ASTVisitor { public: - static std::unique_ptr<Item> derive (Item &item, const Attribute &derive, - BuiltinMacro to_derive); + /** + * Expand a built-in derive macro on an item. This may generate multiple items + * which all need to be integrated to the existing AST + */ + static std::vector<std::unique_ptr<Item>> + derive (Item &item, const Attribute &derive, BuiltinMacro to_derive); protected: DeriveVisitor (location_t loc); @@ -43,6 +47,29 @@ protected: location_t loc; Builder builder; + struct ImplGenerics + { + /* The type we are deriving the impl for */ + std::unique_ptr<Type> self_type; + + /* Generics for the impl itself */ + std::vector<std::unique_ptr<GenericParam>> impl; + }; + + /** + * Create the generic parameters for a derive impl block. Derived impl blocks + * will often share the same structure of reusing the exact same bounds as + * their original type, plus adding an extra one for the trait we are + * deriving. For example, when deriving `Clone` on `Foo<T>`, you want to make + * sure that you implement `Clone` only if `T: Clone` - so you add an extra + * `Clone` bound to all of your generics. + */ + ImplGenerics setup_impl_generics ( + const std::string &type_name, + const std::vector<std::unique_ptr<GenericParam>> &type_generics, + tl::optional<std::unique_ptr<TypeParamBound>> &&extra_bound + = tl::nullopt) const; + private: // the 4 "allowed" visitors, which a derive-visitor can specify and override virtual void visit_struct (StructStruct &struct_item) = 0; @@ -144,6 +171,7 @@ private: virtual void visit (AwaitExpr &expr) override final{}; virtual void visit (AsyncBlockExpr &expr) override final{}; virtual void visit (InlineAsm &expr) override final{}; + virtual void visit (LlvmInlineAsm &expr) override final{}; virtual void visit (TypeParam ¶m) override final{}; virtual void visit (LifetimeWhereClauseItem &item) override final{}; virtual void visit (TypeBoundWhereClauseItem &item) override final{}; diff --git a/gcc/rust/expand/rust-expand-format-args.cc b/gcc/rust/expand/rust-expand-format-args.cc index c8087ee..af6182f 100644 --- a/gcc/rust/expand/rust-expand-format-args.cc +++ b/gcc/rust/expand/rust-expand-format-args.cc @@ -120,7 +120,7 @@ expand_format_args (AST::FormatArgs &fmt, auto pieces = builder.ref (builder.array (std::move (static_pieces))); auto args_slice = builder.ref (builder.array (std::move (args_array))); - auto final_path = make_unique<AST::PathInExpression> ( + auto final_path = std::make_unique<AST::PathInExpression> ( builder.path_in_expression ({"core", "fmt", "Arguments", "new_v1"})); auto final_args = std::vector<std::unique_ptr<AST::Expr>> (); final_args.emplace_back (std::move (pieces)); diff --git a/gcc/rust/expand/rust-expand-visitor.cc b/gcc/rust/expand/rust-expand-visitor.cc index 38399d0d..42df5e1 100644 --- a/gcc/rust/expand/rust-expand-visitor.cc +++ b/gcc/rust/expand/rust-expand-visitor.cc @@ -43,7 +43,7 @@ ExpandVisitor::go (AST::Crate &crate) visit (crate); } -static std::unique_ptr<AST::Item> +static std::vector<std::unique_ptr<AST::Item>> builtin_derive_item (AST::Item &item, const AST::Attribute &derive, BuiltinMacro to_derive) { @@ -189,11 +189,12 @@ ExpandVisitor::expand_inner_items ( to_derive.get ().as_string ()); if (maybe_builtin.has_value ()) { - auto new_item + auto new_items = builtin_derive_item (item, current, maybe_builtin.value ()); - it = items.insert (it, std::move (new_item)); + for (auto &&new_item : new_items) + it = items.insert (it, std::move (new_item)); } else { @@ -276,12 +277,14 @@ ExpandVisitor::expand_inner_stmts (AST::BlockExpr &expr) to_derive.get ().as_string ()); if (maybe_builtin.has_value ()) { - auto new_item + auto new_items = builtin_derive_item (item, current, maybe_builtin.value ()); + // this inserts the derive *before* the item - is it a // problem? - it = stmts.insert (it, std::move (new_item)); + for (auto &&new_item : new_items) + it = stmts.insert (it, std::move (new_item)); } else { @@ -477,14 +480,18 @@ ExpandVisitor::visit (AST::MacroInvocation ¯o_invoc) void ExpandVisitor::visit (AST::PathInExpression &path) { - for (auto &segment : path.get_segments ()) - if (segment.has_generic_args ()) - expand_generic_args (segment.get_generic_args ()); + if (!path.is_lang_item ()) + for (auto &segment : path.get_segments ()) + if (segment.has_generic_args ()) + expand_generic_args (segment.get_generic_args ()); } void ExpandVisitor::visit (AST::TypePathSegmentGeneric &segment) -{} +{ + if (segment.has_generic_args ()) + expand_generic_args (segment.get_generic_args ()); +} void ExpandVisitor::visit (AST::TypePathSegmentFunction &segment) @@ -718,6 +725,12 @@ ExpandVisitor::visit (AST::TypeBoundWhereClauseItem &item) } void +ExpandVisitor::visit (AST::Module &module) +{ + expand_inner_items (module.get_items ()); +} + +void ExpandVisitor::visit (AST::ExternCrate &crate) {} @@ -855,7 +868,7 @@ ExpandVisitor::visit (AST::Trait &trait) std::function<std::unique_ptr<AST::AssociatedItem> (AST::SingleASTNode)> extractor - = [] (AST::SingleASTNode node) { return node.take_trait_item (); }; + = [] (AST::SingleASTNode node) { return node.take_assoc_item (); }; expand_macro_children (MacroExpander::ContextType::TRAIT, trait.get_trait_items (), extractor); @@ -882,7 +895,8 @@ ExpandVisitor::visit (AST::InherentImpl &impl) expand_where_clause (impl.get_where_clause ()); std::function<std::unique_ptr<AST::AssociatedItem> (AST::SingleASTNode)> - extractor = [] (AST::SingleASTNode node) { return node.take_impl_item (); }; + extractor + = [] (AST::SingleASTNode node) { return node.take_assoc_item (); }; expand_macro_children (MacroExpander::ContextType::IMPL, impl.get_impl_items (), extractor); @@ -910,7 +924,7 @@ ExpandVisitor::visit (AST::TraitImpl &impl) std::function<std::unique_ptr<AST::AssociatedItem> (AST::SingleASTNode)> extractor - = [] (AST::SingleASTNode node) { return node.take_trait_impl_item (); }; + = [] (AST::SingleASTNode node) { return node.take_assoc_item (); }; expand_macro_children (MacroExpander::ContextType::TRAIT_IMPL, impl.get_impl_items (), extractor); diff --git a/gcc/rust/expand/rust-expand-visitor.h b/gcc/rust/expand/rust-expand-visitor.h index aca6c93..ad237c0 100644 --- a/gcc/rust/expand/rust-expand-visitor.h +++ b/gcc/rust/expand/rust-expand-visitor.h @@ -140,7 +140,7 @@ public: it = values.erase (it); for (auto &node : final_fragment.get_nodes ()) { - auto new_node = extractor (node); + U new_node = extractor (node); if (new_node != nullptr) { it = values.insert (it, std::move (new_node)); @@ -237,6 +237,7 @@ public: void visit (AST::TypeParam ¶m) override; void visit (AST::LifetimeWhereClauseItem &) override; void visit (AST::TypeBoundWhereClauseItem &item) override; + void visit (AST::Module &module) override; void visit (AST::ExternCrate &crate) override; void visit (AST::UseTreeGlob &) override; void visit (AST::UseTreeList &) override; diff --git a/gcc/rust/expand/rust-macro-builtins-asm.cc b/gcc/rust/expand/rust-macro-builtins-asm.cc index 214265d..e255729 100644 --- a/gcc/rust/expand/rust-macro-builtins-asm.cc +++ b/gcc/rust/expand/rust-macro-builtins-asm.cc @@ -17,11 +17,12 @@ // <http://www.gnu.org/licenses/>. #include "expected.h" -#include "rust-make-unique.h" #include "rust-macro-builtins-asm.h" #include "rust-ast-fragment.h" #include "rust-ast.h" +#include "rust-fmt.h" #include "rust-stmt.h" +#include "rust-parse.h" namespace Rust { std::map<AST::InlineAsmOption, std::string> InlineAsmOptionMap{ @@ -38,6 +39,32 @@ std::map<AST::InlineAsmOption, std::string> InlineAsmOptionMap{ std::set<std::string> potentially_nonpromoted_keywords = {"in", "out", "lateout", "inout", "inlateout", "const", "sym", "label"}; + +// Helper function strips the beginning and ending double quotes from a +// string. +std::string +strip_double_quotes (const std::string &str) +{ + std::string result = str; + + rust_assert (!str.empty ()); + + rust_assert (str.front () == '\"'); + rust_assert (str.back () == '\"'); + + // we have to special case empty strings which just contain a set of quotes + // so, if the string is "\"\"", just return "" + if (result.size () == 2) + return ""; + + rust_assert (result.size () >= 3); + + result.erase (0, 1); + result.erase (result.size () - 1, 1); + + return result; +} + tl::expected<InlineAsmContext, InlineAsmParseError> parse_clobber_abi (InlineAsmContext inline_asm_ctx) { @@ -193,7 +220,6 @@ parse_reg_operand (InlineAsmContext inline_asm_ctx) // None // }; auto &parser = inline_asm_ctx.parser; - AST::InlineAsmOperand reg_operand; auto token = parser.peek_current_token (); auto iden_token = parser.peek_current_token (); @@ -227,20 +253,28 @@ parse_reg_operand (InlineAsmContext inline_asm_ctx) // Loop over and execute the parsing functions, if the parser successfullly // parses or if the parser fails to parse while it has committed to a token, // we propogate the result. + tl::expected<InlineAsmContext, InlineAsmParseError> parsing_operand ( + inline_asm_ctx); for (auto &parse_func : parse_funcs) { - auto parsing_operand - = tl::expected<InlineAsmContext, InlineAsmParseError> (inline_asm_ctx); - parsing_operand.map (parse_func); + auto result = parsing_operand.and_then (parse_func); // Per rust's asm.rs's structure // After we've parse successfully, we break out and do a local validation // of named, positional & explicit register operands - if (parsing_operand.has_value ()) - break; - if (parsing_operand.error () == COMMITTED) - return parsing_operand; + if (result.has_value ()) + { + inline_asm_ctx = *result; + break; + } + else if (result.error () == COMMITTED) + { + if (parse_func == parse_reg_operand_unexpected) + return inline_asm_ctx; + else + return result; + } } auto &inline_asm = inline_asm_ctx.inline_asm; @@ -289,8 +323,8 @@ parse_reg_operand_in (InlineAsmContext inline_asm_ctx) { // For the keyword IN, currently we count it as a seperate keyword called // Rust::IN search for #define RS_TOKEN_LIST in code base. - AST::InlineAsmOperand reg_operand; auto &parser = inline_asm_ctx.parser; + location_t locus = parser.peek_current_token ()->get_locus (); if (!inline_asm_ctx.is_global_asm () && parser.skip_token (IN)) { auto reg = parse_reg (inline_asm_ctx); @@ -300,16 +334,15 @@ parse_reg_operand_in (InlineAsmContext inline_asm_ctx) // We are sure to be failing a test here, based on asm.rs // https://github.com/rust-lang/rust/blob/a330e49593ee890f9197727a3a558b6e6b37f843/compiler/rustc_builtin_macros/src/asm.rs#L112 rust_unreachable (); - return tl::unexpected<InlineAsmParseError> (COMMITTED); + // return tl::unexpected<InlineAsmParseError> (COMMITTED); } - auto expr = parse_format_string (inline_asm_ctx); + auto expr = parser.parse_expr (); // TODO: When we've succesfully parse an expr, remember to clone_expr() // instead of nullptr - // struct AST::InlineAsmOperand::In in (reg, nullptr); - // reg_operand.set_in (in); - // inline_asm_ctx.inline_asm.operands.push_back (reg_operand); + AST::InlineAsmOperand::In in (reg, std::move (expr)); + inline_asm_ctx.inline_asm.operands.emplace_back (in, locus); return inline_asm_ctx; } return tl::unexpected<InlineAsmParseError> (NONCOMMITED); @@ -319,18 +352,22 @@ tl::expected<InlineAsmContext, InlineAsmParseError> parse_reg_operand_out (InlineAsmContext inline_asm_ctx) { auto &parser = inline_asm_ctx.parser; - AST::InlineAsmOperand reg_operand; + location_t locus = parser.peek_current_token ()->get_locus (); if (!inline_asm_ctx.is_global_asm () && check_identifier (parser, "out")) { auto reg = parse_reg (inline_asm_ctx); + std::unique_ptr<AST::Expr> expr = parser.parse_expr (); - auto expr = parse_format_string (inline_asm_ctx); + rust_assert (expr != nullptr); + + /*auto expr_ptr = + std::make_unique<AST::Expr>(AST::LiteralExpr(Literal))*/ // TODO: When we've succesfully parse an expr, remember to clone_expr() // instead of nullptr - // struct AST::InlineAsmOperand::Out out (reg, false, nullptr); - // reg_operand.set_out (out); - // inline_asm_ctx.inline_asm.operands.push_back (reg_operand); + AST::InlineAsmOperand::Out out (reg, false, std::move (expr)); + + inline_asm_ctx.inline_asm.operands.emplace_back (out, locus); return inline_asm_ctx; } @@ -360,7 +397,6 @@ parse_reg_operand_inout (InlineAsmContext inline_asm_ctx) auto &parser = inline_asm_ctx.parser; auto token = parser.peek_current_token (); - AST::InlineAsmOperand reg_operand; if (!inline_asm_ctx.is_global_asm () && check_identifier (parser, "inout")) { auto reg = parse_reg (inline_asm_ctx); @@ -378,7 +414,9 @@ parse_reg_operand_inout (InlineAsmContext inline_asm_ctx) // TODO: Is error propogation our top priority, the ? in rust's asm.rs is // doing a lot of work. // TODO: Not sure how to use parse_expr - auto expr = parse_format_string (inline_asm_ctx); + if (!check_identifier (parser, "")) + rust_unreachable (); + // auto expr = parse_format_string (inline_asm_ctx); std::unique_ptr<AST::Expr> out_expr; @@ -386,9 +424,9 @@ parse_reg_operand_inout (InlineAsmContext inline_asm_ctx) { if (!parser.skip_token (UNDERSCORE)) { - auto result = parse_format_string (inline_asm_ctx); + // auto result = parse_format_string (inline_asm_ctx); - if (!result.has_value ()) + if (!check_identifier (parser, "")) rust_unreachable (); // out_expr = parser.parse_expr(); } @@ -399,8 +437,8 @@ parse_reg_operand_inout (InlineAsmContext inline_asm_ctx) // expr, out_expr, late: false } // struct AST::InlineAsmOperand::SplitInOut split_in_out (reg, // false, nullptr, - // nullptr); reg_operand.set_split_in_out (split_in_out); - // inline_asm_ctx.inline_asm.operands.push_back (reg_operand); + // nullptr); + // inline_asm_ctx.inline_asm.operands.push_back (split_in_out); return inline_asm_ctx; } @@ -410,8 +448,8 @@ parse_reg_operand_inout (InlineAsmContext inline_asm_ctx) // RUST VERSION: ast::InlineAsmOperand::InOut { reg, expr, late: false // } // struct AST::InlineAsmOperand::InOut inout (reg, false, - // nullptr); reg_operand.set_in_out (inout); - // inline_asm_ctx.inline_asm.operands.push_back (reg_operand); + // nullptr); + // inline_asm_ctx.inline_asm.operands.push_back (inout); return inline_asm_ctx; } } @@ -423,12 +461,10 @@ tl::expected<InlineAsmContext, InlineAsmParseError> parse_reg_operand_const (InlineAsmContext inline_asm_ctx) { auto &parser = inline_asm_ctx.parser; - AST::InlineAsmOperand reg_operand; if (parser.peek_current_token ()->get_id () == CONST) { // TODO: Please handle const with parse_expr instead. auto anon_const = parse_format_string (inline_asm_ctx); - reg_operand.set_cnst (tl::nullopt); rust_unreachable (); return tl::unexpected<InlineAsmParseError> (COMMITTED); } @@ -457,9 +493,9 @@ parse_reg_operand_unexpected (InlineAsmContext inline_asm_ctx) // TODO: It is weird that we can't seem to match any identifier, // something must be wrong. consult compiler code in asm.rs or rust online // compiler. - rust_unreachable (); + // rust_unreachable (); - rust_error_at (token->get_locus (), "ERROR RIGHT HERE"); + // rust_error_at (token->get_locus (), "ERROR RIGHT HERE"); return tl::unexpected<InlineAsmParseError> (COMMITTED); } @@ -551,9 +587,7 @@ parse_options (InlineAsmContext &inline_asm_ctx) // Parse comma as optional if (parser.skip_token (COMMA)) - { - continue; - } + continue; else { rust_unreachable (); @@ -627,6 +661,15 @@ MacroBuiltin::asm_handler (location_t invoc_locus, AST::MacroInvocData &invoc, return parse_asm (invoc_locus, invoc, semicolon, is_global_asm); } +tl::optional<AST::Fragment> +MacroBuiltin::llvm_asm_handler (location_t invoc_locus, + AST::MacroInvocData &invoc, + AST::InvocKind semicolon, + AST::AsmKind is_global_asm) +{ + return parse_llvm_asm (invoc_locus, invoc, semicolon, is_global_asm); +} + tl::expected<InlineAsmContext, InlineAsmParseError> parse_asm_arg (InlineAsmContext inline_asm_ctx) { @@ -638,6 +681,14 @@ parse_asm_arg (InlineAsmContext inline_asm_ctx) { token = parser.peek_current_token (); + if (token->get_id () == COLON || token->get_id () == SCOPE_RESOLUTION) + { + rust_error_at ( + token->get_locus (), + "the legacy LLVM-style %<asm!%> syntax is no longer supported"); + return tl::unexpected<InlineAsmParseError> (COMMITTED); + } + // We accept a comma token here. if (token->get_id () != COMMA && inline_asm_ctx.consumed_comma_without_formatted_string) @@ -678,7 +729,9 @@ parse_asm_arg (InlineAsmContext inline_asm_ctx) if (check_identifier (parser, "clobber_abi")) { auto expected = parse_clobber_abi (inline_asm_ctx); - if (expected || expected.error () == COMMITTED) + if (expected.has_value ()) + continue; + else if (expected.error () == COMMITTED) return expected; // The error type is definitely non-committed (we have checked above), @@ -688,7 +741,9 @@ parse_asm_arg (InlineAsmContext inline_asm_ctx) if (check_identifier (parser, "options")) { auto expected = parse_options (inline_asm_ctx); - if (expected || expected.error () == COMMITTED) + if (expected.has_value ()) + continue; + else if (expected.error () == COMMITTED) return expected; // The error type is definitely non-committed (we have checked above), @@ -699,7 +754,9 @@ parse_asm_arg (InlineAsmContext inline_asm_ctx) // only other logical choice is reg_operand auto expected = parse_reg_operand (inline_asm_ctx); - if (expected || expected.error () == COMMITTED) + if (expected.has_value ()) + continue; + else if (expected.error () == COMMITTED) return expected; // Since parse_reg_operand is the last thing we've considered, @@ -718,6 +775,74 @@ parse_asm_arg (InlineAsmContext inline_asm_ctx) return tl::expected<InlineAsmContext, InlineAsmParseError> (inline_asm_ctx); } +tl::expected<InlineAsmContext, InlineAsmParseError> +expand_inline_asm_strings (InlineAsmContext inline_asm_ctx) +{ + auto &inline_asm = inline_asm_ctx.inline_asm; + + auto str_vec = inline_asm.get_template_strs (); + + decltype (str_vec) resulting_template_vec; + for (auto &template_str : str_vec) + { + /*std::cout << template_str.symbol << std::endl;*/ + + auto pieces = Fmt::Pieces::collect (template_str.symbol, false, + Fmt::ffi::ParseMode::InlineAsm); + auto pieces_vec = pieces.get_pieces (); + + std::string transformed_template_str = ""; + for (size_t i = 0; i < pieces_vec.size (); i++) + { + auto piece = pieces_vec[i]; + if (piece.tag == Fmt::ffi::Piece::Tag::String) + { + transformed_template_str += piece.string._0.to_string (); + } + else if (piece.tag == Fmt::ffi::Piece::Tag::NextArgument) + { + /* std::cout << " " << i << ": "*/ + /*<< piece.next_argument._0.to_string () << std::endl;*/ + + auto next_argument = piece.next_argument._0; + switch (piece.next_argument._0.position.tag) + { + case Fmt::ffi::Position::Tag::ArgumentImplicitlyIs: { + auto idx = next_argument.position.argument_implicitly_is._0; + /*auto trait = next_argument.format;*/ + /*auto arg = arguments.at (idx);*/ + + /* // FIXME(Arthur): This API sucks*/ + /* rust_assert (arg.get_kind ().kind*/ + /*== AST::FormatArgumentKind::Kind::Normal);*/ + /**/ + /* args.push_back ({arg.get_expr ().clone_expr (), + * trait});*/ + + transformed_template_str += "%" + std::to_string (idx); + // std::cout << "argument implicitly is: " << idx << + // std::endl; std::cout << "transformed template str is:" + // << transformed_template_str << std::endl; + /*std::cout << "trait: " << trait.to_string () << + * std::endl;*/ + /*std::cout << "arg: " << arg.to_string () << std::endl;*/ + } + break; + case Fmt::ffi::Position::Tag::ArgumentIs: + case Fmt::ffi::Position::Tag::ArgumentNamed: + rust_sorry_at (inline_asm.get_locus (), + "unhandled argument position specifier"); + break; + } + } + } + template_str.symbol = transformed_template_str; + } + + inline_asm.template_strs = str_vec; + return inline_asm_ctx; +} + tl::optional<AST::Fragment> parse_asm (location_t invoc_locus, AST::MacroInvocData &invoc, AST::InvocKind semicolon, AST::AsmKind is_global_asm) @@ -726,7 +851,8 @@ parse_asm (location_t invoc_locus, AST::MacroInvocData &invoc, // We first parse all formatted strings. If we fail, then we return // tl::nullopt - // We then parse the asm arguments. If we fail, then we return tl::nullopt + // We then parse the asm arguments. If we fail, then we return + // tl::nullopt // We then validate. If we fail, then we return tl::nullopt @@ -741,26 +867,27 @@ parse_asm (location_t invoc_locus, AST::MacroInvocData &invoc, auto resulting_context = parse_format_strings (inline_asm_ctx) .and_then (parse_asm_arg) - .and_then (validate); - - // TODO: I'm putting the validation here because the rust reference put it - // here Per Arthur's advice we would actually do the validation in a different - // stage. and visit on the InlineAsm AST instead of it's context. - auto is_valid = (bool) resulting_context; - - if (is_valid) + .and_then (validate) + .and_then (expand_inline_asm_strings); + + // TODO: I'm putting the validation here because the rust reference put + // it here Per Arthur's advice we would actually do the validation in a + // different stage. and visit on the InlineAsm AST instead of it's + // context. + if (resulting_context) { - auto node = inline_asm_ctx.inline_asm.clone_expr_without_block (); + auto node = (*resulting_context).inline_asm.clone_expr_without_block (); std::vector<AST::SingleASTNode> single_vec = {}; - // If the macro invocation has a semicolon (`asm!("...");`), then we need - // to make it a statement. This way, it will be expanded properly. + // If the macro invocation has a semicolon (`asm!("...");`), then we + // need to make it a statement. This way, it will be expanded + // properly. if (semicolon == AST::InvocKind::Semicoloned) single_vec.emplace_back (AST::SingleASTNode ( - Rust::make_unique<AST::ExprStmt> (std::move (node), invoc_locus, - semicolon - == AST::InvocKind::Semicoloned))); + std::make_unique<AST::ExprStmt> (std::move (node), invoc_locus, + semicolon + == AST::InvocKind::Semicoloned))); else single_vec.emplace_back (AST::SingleASTNode (std::move (node))); @@ -778,7 +905,8 @@ parse_asm (location_t invoc_locus, AST::MacroInvocData &invoc, tl::expected<InlineAsmContext, InlineAsmParseError> parse_format_strings (InlineAsmContext inline_asm_ctx) { - // Parse the first ever formatted string, success or not, will skip 1 token + // Parse the first ever formatted string, success or not, will skip 1 + // token auto &parser = inline_asm_ctx.parser; auto last_token_id = inline_asm_ctx.last_token_id; auto fm_string = parse_format_string (inline_asm_ctx); @@ -794,7 +922,8 @@ parse_format_strings (InlineAsmContext inline_asm_ctx) else { auto template_str - = AST::TupleTemplateStr (token->get_locus (), fm_string.value ()); + = AST::TupleTemplateStr (token->get_locus (), + strip_double_quotes (fm_string.value ())); inline_asm.template_strs.push_back (template_str); } @@ -806,8 +935,8 @@ parse_format_strings (InlineAsmContext inline_asm_ctx) { break; } - // Ok after the comma is good, we better be parsing correctly everything - // in here, which is formatted string in ABNF + // Ok after the comma is good, we better be parsing correctly + // everything in here, which is formatted string in ABNF inline_asm_ctx.consumed_comma_without_formatted_string = false; token = parser.peek_current_token (); @@ -820,7 +949,8 @@ parse_format_strings (InlineAsmContext inline_asm_ctx) else { auto template_str - = AST::TupleTemplateStr (token->get_locus (), fm_string.value ()); + = AST::TupleTemplateStr (token->get_locus (), + strip_double_quotes (fm_string.value ())); inline_asm.template_strs.push_back (template_str); } } @@ -850,4 +980,223 @@ validate (InlineAsmContext inline_asm_ctx) { return tl::expected<InlineAsmContext, InlineAsmParseError> (inline_asm_ctx); } + +tl::optional<LlvmAsmContext> +parse_llvm_templates (LlvmAsmContext ctx) +{ + auto &parser = ctx.parser; + + auto token = parser.peek_current_token (); + + if (token->get_id () == ctx.last_token_id + || token->get_id () != STRING_LITERAL) + { + return tl::nullopt; + } + + ctx.llvm_asm.get_templates ().emplace_back (token->get_locus (), + strip_double_quotes ( + token->as_string ())); + ctx.parser.skip_token (); + + token = parser.peek_current_token (); + if (token->get_id () != ctx.last_token_id && token->get_id () != COLON + && token->get_id () != SCOPE_RESOLUTION) + { + // We do not handle multiple template string, we provide minimal support + // for the black_box intrinsics. + rust_unreachable (); + } + + return ctx; +} + +tl::optional<LlvmAsmContext> +parse_llvm_arguments (LlvmAsmContext ctx) +{ + auto &parser = ctx.parser; + enum State + { + Templates = 0, + Output, + Input, + Clobbers, + Options + } current_state + = State::Templates; + + while (parser.peek_current_token ()->get_id () != ctx.last_token_id + && parser.peek_current_token ()->get_id () != END_OF_FILE) + { + if (parser.peek_current_token ()->get_id () == SCOPE_RESOLUTION) + { + parser.skip_token (SCOPE_RESOLUTION); + current_state = static_cast<State> (current_state + 2); + } + else + { + parser.skip_token (COLON); + current_state = static_cast<State> (current_state + 1); + } + + switch (current_state) + { + case State::Output: + parse_llvm_outputs (ctx); + break; + case State::Input: + parse_llvm_inputs (ctx); + break; + case State::Clobbers: + parse_llvm_clobbers (ctx); + break; + case State::Options: + parse_llvm_options (ctx); + break; + case State::Templates: + default: + rust_unreachable (); + } + } + + return ctx; +} + +void +parse_llvm_operands (LlvmAsmContext &ctx, std::vector<AST::LlvmOperand> &result) +{ + auto &parser = ctx.parser; + auto token = parser.peek_current_token (); + while (token->get_id () != COLON && token->get_id () != SCOPE_RESOLUTION + && token->get_id () != ctx.last_token_id) + { + std::string constraint; + if (token->get_id () == STRING_LITERAL) + { + constraint = strip_double_quotes (token->as_string ()); + } + parser.skip_token (STRING_LITERAL); + parser.skip_token (LEFT_PAREN); + + token = parser.peek_current_token (); + + ParseRestrictions restrictions; + restrictions.expr_can_be_null = true; + auto expr = parser.parse_expr (); + + parser.skip_token (RIGHT_PAREN); + + result.emplace_back (constraint, std::move (expr)); + + if (parser.peek_current_token ()->get_id () == COMMA) + parser.skip_token (COMMA); + + token = parser.peek_current_token (); + } +} + +void +parse_llvm_outputs (LlvmAsmContext &ctx) +{ + parse_llvm_operands (ctx, ctx.llvm_asm.get_outputs ()); +} + +void +parse_llvm_inputs (LlvmAsmContext &ctx) +{ + parse_llvm_operands (ctx, ctx.llvm_asm.get_inputs ()); +} + +void +parse_llvm_clobbers (LlvmAsmContext &ctx) +{ + auto &parser = ctx.parser; + auto token = parser.peek_current_token (); + while (token->get_id () != COLON && token->get_id () != ctx.last_token_id) + { + if (token->get_id () == STRING_LITERAL) + { + ctx.llvm_asm.get_clobbers ().push_back ( + {strip_double_quotes (token->as_string ()), token->get_locus ()}); + } + parser.skip_token (STRING_LITERAL); + token = parser.peek_current_token (); + } +} + +void +parse_llvm_options (LlvmAsmContext &ctx) +{ + auto &parser = ctx.parser; + auto token = parser.peek_current_token (); + + while (token->get_id () != ctx.last_token_id) + { + if (token->get_id () == STRING_LITERAL) + { + auto token_str = strip_double_quotes (token->as_string ()); + + if (token_str == "volatile") + ctx.llvm_asm.set_volatile (true); + else if (token_str == "alignstack") + ctx.llvm_asm.set_align_stack (true); + else if (token_str == "intel") + ctx.llvm_asm.set_dialect (AST::LlvmInlineAsm::Dialect::Intel); + else + rust_error_at (token->get_locus (), + "Unknown llvm assembly option %qs", + token_str.c_str ()); + } + parser.skip_token (STRING_LITERAL); + + token = parser.peek_current_token (); + + if (token->get_id () == ctx.last_token_id) + continue; + parser.skip_token (COMMA); + } + + parser.skip_token (); +} + +tl::optional<AST::Fragment> +parse_llvm_asm (location_t invoc_locus, AST::MacroInvocData &invoc, + AST::InvocKind semicolon, AST::AsmKind is_global_asm) +{ + MacroInvocLexer lex (invoc.get_delim_tok_tree ().to_token_stream ()); + Parser<MacroInvocLexer> parser (lex); + auto last_token_id = macro_end_token (invoc.get_delim_tok_tree (), parser); + + AST::LlvmInlineAsm llvm_asm{invoc_locus}; + + auto asm_ctx = LlvmAsmContext (llvm_asm, parser, last_token_id); + + auto resulting_context + = parse_llvm_templates (asm_ctx).and_then (parse_llvm_arguments); + + if (resulting_context) + { + auto node = (*resulting_context).llvm_asm.clone_expr_without_block (); + + std::vector<AST::SingleASTNode> single_vec = {}; + + // If the macro invocation has a semicolon (`asm!("...");`), then we + // need to make it a statement. This way, it will be expanded + // properly. + if (semicolon == AST::InvocKind::Semicoloned) + single_vec.emplace_back (AST::SingleASTNode ( + std::make_unique<AST::ExprStmt> (std::move (node), invoc_locus, + semicolon + == AST::InvocKind::Semicoloned))); + else + single_vec.emplace_back (AST::SingleASTNode (std::move (node))); + + AST::Fragment fragment_ast + = AST::Fragment (single_vec, + std::vector<std::unique_ptr<AST::Token>> ()); + return fragment_ast; + } + return tl::nullopt; +} + } // namespace Rust diff --git a/gcc/rust/expand/rust-macro-builtins-asm.h b/gcc/rust/expand/rust-macro-builtins-asm.h index 6997770..bd64a7f 100644 --- a/gcc/rust/expand/rust-macro-builtins-asm.h +++ b/gcc/rust/expand/rust-macro-builtins-asm.h @@ -65,6 +65,14 @@ public: // { // } + InlineAsmContext &operator= (const InlineAsmContext &inline_asm_ctx) + { + allow_templates = inline_asm_ctx.allow_templates; + is_explicit = inline_asm_ctx.is_explicit; + consumed_comma_without_formatted_string = false; + last_token_id = inline_asm_ctx.last_token_id; + return *this; + } bool is_global_asm () { return inline_asm.is_global_asm; } @@ -75,6 +83,9 @@ public: this->allow_templates = allow_templates; } }; +WARN_UNUSED_RESULT +tl::expected<InlineAsmContext, InlineAsmParseError> +expand_inline_asm_strings (InlineAsmContext inline_asm_ctx); // Expected calls WARN_UNUSED_RESULT @@ -161,4 +172,36 @@ tl::optional<std::string> parse_label (Parser<MacroInvocLexer> &parser, TokenId last_token_id, InlineAsmContext &inline_asm_ctx); -} // namespace Rust
\ No newline at end of file +// LLVM ASM bits + +class LlvmAsmContext +{ +public: + AST::LlvmInlineAsm &llvm_asm; + Parser<MacroInvocLexer> &parser; + int last_token_id; + +public: + LlvmAsmContext (AST::LlvmInlineAsm &llvm_asm, Parser<MacroInvocLexer> &parser, + int last_token_id) + : llvm_asm (llvm_asm), parser (parser), last_token_id (last_token_id) + {} +}; + +void +parse_llvm_outputs (LlvmAsmContext &ctx); + +void +parse_llvm_inputs (LlvmAsmContext &ctx); + +void +parse_llvm_clobbers (LlvmAsmContext &ctx); + +void +parse_llvm_options (LlvmAsmContext &ctx); + +WARN_UNUSED_RESULT tl::optional<AST::Fragment> +parse_llvm_asm (location_t invoc_locus, AST::MacroInvocData &invoc, + AST::InvocKind semicolon, AST::AsmKind is_global_asm); + +} // namespace Rust diff --git a/gcc/rust/expand/rust-macro-builtins-format-args.cc b/gcc/rust/expand/rust-macro-builtins-format-args.cc index 8eb32d5..3e1249d 100644 --- a/gcc/rust/expand/rust-macro-builtins-format-args.cc +++ b/gcc/rust/expand/rust-macro-builtins-format-args.cc @@ -55,6 +55,8 @@ format_args_parse_arguments (AST::MacroInvocData &invoc) if (parser.peek_current_token ()->get_id () == STRING_LITERAL) format_expr = parser.parse_literal_expr (); + rust_assert (format_expr); + // TODO(Arthur): Clean this up - if we haven't parsed a string literal but a // macro invocation, what do we do here? return a tl::unexpected? auto format_str = static_cast<AST::LiteralExpr &> (*format_expr) @@ -81,6 +83,11 @@ format_args_parse_arguments (AST::MacroInvocData &invoc) { parser.skip_token (COMMA); + // Check in case of an extraneous comma in the args list, which is + // allowed - format_args!("fmt", arg, arg2,) + if (parser.peek_current_token ()->get_id () == last_token_id) + break; + if (parser.peek_current_token ()->get_id () == IDENTIFIER && parser.peek (1)->get_id () == EQUAL) { diff --git a/gcc/rust/expand/rust-macro-builtins-helpers.cc b/gcc/rust/expand/rust-macro-builtins-helpers.cc index d44efcc..864379a 100644 --- a/gcc/rust/expand/rust-macro-builtins-helpers.cc +++ b/gcc/rust/expand/rust-macro-builtins-helpers.cc @@ -36,7 +36,7 @@ check_for_eager_invocations ( std::vector<std::unique_ptr<AST::MacroInvocation>> pending; for (auto &expr : expressions) - if (expr->get_ast_kind () == AST::Kind::MACRO_INVOCATION) + if (expr->get_expr_kind () == AST::Expr::Kind::MacroInvocation) pending.emplace_back (std::unique_ptr<AST::MacroInvocation> ( static_cast<AST::MacroInvocation *> (expr->clone_expr ().release ()))); @@ -174,7 +174,8 @@ try_expand_many_expr (Parser<MacroInvocLexer> &parser, std::unique_ptr<AST::Expr> parse_single_string_literal (BuiltinMacro kind, AST::DelimTokenTree &invoc_token_tree, - location_t invoc_locus, MacroExpander *expander) + location_t invoc_locus, MacroExpander *expander, + bool is_semicoloned) { MacroInvocLexer lex (invoc_token_tree.to_token_stream ()); Parser<MacroInvocLexer> parser (lex); @@ -221,7 +222,7 @@ parse_single_string_literal (BuiltinMacro kind, AST::MacroInvocData (AST::SimplePath ({AST::SimplePathSegment ( path_str, invoc_locus)}), std::move (invoc_token_tree)), - {}, invoc_locus, std::move (pending_invocations)); + {}, invoc_locus, std::move (pending_invocations), is_semicoloned); } else { @@ -281,4 +282,4 @@ load_file_bytes (location_t invoc_locus, const char *filename) return buf; } -} // namespace Rust
\ No newline at end of file +} // namespace Rust diff --git a/gcc/rust/expand/rust-macro-builtins-helpers.h b/gcc/rust/expand/rust-macro-builtins-helpers.h index bf058df..429537e 100644 --- a/gcc/rust/expand/rust-macro-builtins-helpers.h +++ b/gcc/rust/expand/rust-macro-builtins-helpers.h @@ -29,7 +29,6 @@ #include "rust-macro-invoc-lexer.h" #include "rust-macro.h" #include "rust-parse.h" -#include "rust-session-manager.h" #include "rust-system.h" #include "rust-token.h" namespace Rust { @@ -74,7 +73,8 @@ try_expand_many_expr (Parser<MacroInvocLexer> &parser, std::unique_ptr<AST::Expr> parse_single_string_literal (BuiltinMacro kind, AST::DelimTokenTree &invoc_token_tree, - location_t invoc_locus, MacroExpander *expander); + location_t invoc_locus, MacroExpander *expander, + bool is_semicoloned = false); // Treat PATH as a path relative to the source file currently being // compiled, and return the absolute path for it. diff --git a/gcc/rust/expand/rust-macro-builtins-include.cc b/gcc/rust/expand/rust-macro-builtins-include.cc index cf3f93d..2ab2a3a 100644 --- a/gcc/rust/expand/rust-macro-builtins-include.cc +++ b/gcc/rust/expand/rust-macro-builtins-include.cc @@ -20,6 +20,7 @@ #include "rust-common.h" #include "rust-macro-builtins.h" #include "rust-macro-builtins-helpers.h" +#include "rust-session-manager.h" #include "optional.h" namespace Rust { /* Expand builtin macro include_bytes!("filename"), which includes the contents @@ -40,7 +41,12 @@ MacroBuiltin::include_bytes_handler (location_t invoc_locus, if (lit_expr == nullptr) return AST::Fragment::create_error (); - rust_assert (lit_expr->is_literal ()); + if (!lit_expr->is_literal ()) + { + auto token_tree = invoc.get_delim_tok_tree (); + return AST::Fragment ({AST::SingleASTNode (std::move (lit_expr))}, + token_tree.to_token_stream ()); + } std::string target_filename = source_relative_path (lit_expr->as_string (), invoc_locus); @@ -188,16 +194,36 @@ MacroBuiltin::include_handler (location_t invoc_locus, AST::MacroInvocData &invoc, AST::InvocKind semicolon) { + bool is_semicoloned = semicolon == AST::InvocKind::Semicoloned; /* Get target filename from the macro invocation, which is treated as a path relative to the include!-ing file (currently being compiled). */ - auto lit_expr + std::unique_ptr<AST::Expr> lit_expr = parse_single_string_literal (BuiltinMacro::Include, invoc.get_delim_tok_tree (), invoc_locus, - invoc.get_expander ()); + invoc.get_expander (), is_semicoloned); if (lit_expr == nullptr) return AST::Fragment::create_error (); - rust_assert (lit_expr->is_literal ()); + if (!lit_expr->is_literal ()) + { + // We have to expand an inner macro eagerly + auto token_tree = invoc.get_delim_tok_tree (); + + // parse_single_string_literal returned an AST::MacroInvocation, which + // can either be an AST::Item or AST::Expr. Depending on the context the + // original macro was invoked in, we will set AST::Item or AST::Expr + // appropriately. + if (is_semicoloned) + { + std::unique_ptr<AST::Item> lit_item = std::unique_ptr<AST::Item> ( + static_cast<AST::MacroInvocation *> (lit_expr.release ())); + return AST::Fragment ({AST::SingleASTNode (std::move (lit_item))}, + token_tree.to_token_stream ()); + } + else + return AST::Fragment ({AST::SingleASTNode (std::move (lit_expr))}, + token_tree.to_token_stream ()); + } std::string filename = source_relative_path (lit_expr->as_string (), invoc_locus); @@ -218,8 +244,14 @@ MacroBuiltin::include_handler (location_t invoc_locus, Lexer lex (target_filename, std::move (target_file), linemap); Parser<Lexer> parser (lex); + std::unique_ptr<AST::Expr> parsed_expr = nullptr; + std::vector<std::unique_ptr<AST::Item>> parsed_items{}; + + if (is_semicoloned) + parsed_items = parser.parse_items (); + else + parsed_expr = parser.parse_expr (); - auto parsed_items = parser.parse_items (); bool has_error = !parser.get_errors ().empty (); for (const auto &error : parser.get_errors ()) @@ -233,17 +265,22 @@ MacroBuiltin::include_handler (location_t invoc_locus, } std::vector<AST::SingleASTNode> nodes{}; - for (auto &item : parsed_items) + if (is_semicoloned) + for (auto &item : parsed_items) + { + AST::SingleASTNode node (std::move (item)); + nodes.push_back (node); + } + else { - AST::SingleASTNode node (std::move (item)); + AST::SingleASTNode node (std::move (parsed_expr)); nodes.push_back (node); } - // FIXME: This returns an empty vector of tokens and works fine, but is that // the expected behavior? `include` macros are a bit harder to reason about // since they include tokens. Furthermore, our lexer has no easy way to return // a slice of tokens like the MacroInvocLexer. So it gets even harder to - // extrac tokens from here. For now, let's keep it that way and see if it + // extract tokens from here. For now, let's keep it that way and see if it // eventually breaks, but I don't expect it to cause many issues since the // list of tokens is only used when a macro invocation mixes eager // macro invocations and already expanded tokens. Think diff --git a/gcc/rust/expand/rust-macro-builtins-log-debug.cc b/gcc/rust/expand/rust-macro-builtins-log-debug.cc index 49670d2..3d7b54f 100644 --- a/gcc/rust/expand/rust-macro-builtins-log-debug.cc +++ b/gcc/rust/expand/rust-macro-builtins-log-debug.cc @@ -30,4 +30,4 @@ MacroBuiltin::assert_handler (location_t invoc_locus, return AST::Fragment::create_error (); } -} // namespace Rust
\ No newline at end of file +} // namespace Rust diff --git a/gcc/rust/expand/rust-macro-builtins-utility.cc b/gcc/rust/expand/rust-macro-builtins-utility.cc index 2da7d18..b20b479 100644 --- a/gcc/rust/expand/rust-macro-builtins-utility.cc +++ b/gcc/rust/expand/rust-macro-builtins-utility.cc @@ -17,8 +17,10 @@ // <http://www.gnu.org/licenses/>. #include "rust-fmt.h" +#include "rust-ast-builder.h" #include "rust-macro-builtins.h" #include "rust-macro-builtins-helpers.h" +#include "rust-session-manager.h" namespace Rust { @@ -117,7 +119,7 @@ MacroBuiltin::concat_handler (location_t invoc_locus, for (auto &expr : expanded_expr) { if (!expr->is_literal () - && expr->get_ast_kind () != AST::Kind::MACRO_INVOCATION) + && expr->get_expr_kind () != AST::Expr::Kind::MacroInvocation) { has_error = true; rust_error_at (expr->get_locus (), "expected a literal"); @@ -226,6 +228,83 @@ MacroBuiltin::env_handler (location_t invoc_locus, AST::MacroInvocData &invoc, return AST::Fragment ({node}, std::move (tok)); } +/* Expand builtin macro option_env!(), which inspects an environment variable at + compile time. */ +tl::optional<AST::Fragment> +MacroBuiltin::option_env_handler (location_t invoc_locus, + AST::MacroInvocData &invoc, + AST::InvocKind semicolon) +{ + auto invoc_token_tree = invoc.get_delim_tok_tree (); + MacroInvocLexer lex (invoc_token_tree.to_token_stream ()); + Parser<MacroInvocLexer> parser (lex); + + auto last_token_id = macro_end_token (invoc_token_tree, parser); + std::unique_ptr<AST::LiteralExpr> lit_expr = nullptr; + bool has_error = false; + + auto start = lex.get_offs (); + auto expanded_expr = try_expand_many_expr (parser, last_token_id, + invoc.get_expander (), has_error); + auto end = lex.get_offs (); + + auto tokens = lex.get_token_slice (start, end); + + if (has_error) + return AST::Fragment::create_error (); + + auto pending = check_for_eager_invocations (expanded_expr); + if (!pending.empty ()) + return make_eager_builtin_invocation (BuiltinMacro::OptionEnv, invoc_locus, + invoc_token_tree, + std::move (pending)); + + if (expanded_expr.size () != 1) + { + rust_error_at (invoc_locus, "%<option_env!%> takes 1 argument"); + return AST::Fragment::create_error (); + } + + if (expanded_expr.size () > 0) + if (!(lit_expr + = try_extract_string_literal_from_fragment (invoc_locus, + expanded_expr[0]))) + return AST::Fragment::create_error (); + + parser.skip_token (last_token_id); + + auto env_value = getenv (lit_expr->as_string ().c_str ()); + AST::Builder b (invoc_locus); + + if (env_value == nullptr) + { + auto none_expr = std::unique_ptr<AST::Expr> ( + new AST::PathInExpression (LangItem::Kind::OPTION_NONE, {}, + invoc_locus)); + + auto node = AST::SingleASTNode (std::move (none_expr)); + std::vector<AST::SingleASTNode> nodes; + nodes.push_back (node); + + return AST::Fragment (nodes, std::vector<std::unique_ptr<AST::Token>> ()); + } + std::vector<std::unique_ptr<AST::Expr>> args; + args.push_back (b.literal_string (env_value)); + + std::unique_ptr<AST::Expr> some_expr + = b.call (std::unique_ptr<AST::Expr> ( + new AST::PathInExpression (LangItem::Kind::OPTION_SOME, {}, + invoc_locus)), + std::move (args)); + + auto node = AST::SingleASTNode (std::move (some_expr)); + + std::vector<AST::SingleASTNode> nodes; + nodes.push_back (node); + + return AST::Fragment (nodes, std::vector<std::unique_ptr<AST::Token>> ()); +} + tl::optional<AST::Fragment> MacroBuiltin::cfg_handler (location_t invoc_locus, AST::MacroInvocData &invoc, AST::InvocKind semicolon) @@ -296,4 +375,4 @@ MacroBuiltin::stringify_handler (location_t invoc_locus, return AST::Fragment ({node}, std::move (token)); } -} // namespace Rust
\ No newline at end of file +} // namespace Rust diff --git a/gcc/rust/expand/rust-macro-builtins.cc b/gcc/rust/expand/rust-macro-builtins.cc index 2457bc0..b58ed71 100644 --- a/gcc/rust/expand/rust-macro-builtins.cc +++ b/gcc/rust/expand/rust-macro-builtins.cc @@ -62,6 +62,8 @@ const BiMap<std::string, BuiltinMacro> MacroBuiltin::builtins = {{ {"concat_idents", BuiltinMacro::ConcatIdents}, {"module_path", BuiltinMacro::ModulePath}, {"asm", BuiltinMacro::Asm}, + // FIXME: Is that okay + {"llvm_asm", BuiltinMacro::Asm}, {"global_asm", BuiltinMacro::GlobalAsm}, {"log_syntax", BuiltinMacro::LogSyntax}, {"trace_macros", BuiltinMacro::TraceMacros}, @@ -81,7 +83,6 @@ const BiMap<std::string, BuiltinMacro> MacroBuiltin::builtins = {{ {"Ord", BuiltinMacro::Ord}, {"PartialOrd", BuiltinMacro::PartialOrd}, {"Hash", BuiltinMacro::Hash}, - }}; AST::MacroTranscriberFunc @@ -102,6 +103,15 @@ inline_asm_maker (AST::AsmKind global_asm) }; } +AST::MacroTranscriberFunc +inline_llvm_asm_maker (AST::AsmKind global_asm) +{ + return [global_asm] (location_t loc, AST::MacroInvocData &invoc, + AST::InvocKind semicolon) { + return MacroBuiltin::llvm_asm_handler (loc, invoc, semicolon, global_asm); + }; +} + std::unordered_map<std::string, AST::MacroTranscriberFunc> MacroBuiltin::builtin_transcribers = { {"assert", MacroBuiltin::assert_handler}, @@ -119,9 +129,11 @@ std::unordered_map<std::string, AST::MacroTranscriberFunc> {"format_args", format_args_maker (AST::FormatArgs::Newline::No)}, {"format_args_nl", format_args_maker (AST::FormatArgs::Newline::Yes)}, {"asm", inline_asm_maker (AST::AsmKind::Inline)}, + // FIXME: Is that okay? + {"llvm_asm", inline_llvm_asm_maker (AST::AsmKind::Inline)}, {"global_asm", inline_asm_maker (AST::AsmKind::Global)}, + {"option_env", MacroBuiltin::option_env_handler}, /* Unimplemented macro builtins */ - {"option_env", MacroBuiltin::sorry}, {"concat_idents", MacroBuiltin::sorry}, {"module_path", MacroBuiltin::sorry}, {"log_syntax", MacroBuiltin::sorry}, @@ -133,6 +145,7 @@ std::unordered_map<std::string, AST::MacroTranscriberFunc> {"cfg_accessible", MacroBuiltin::sorry}, {"rustc_const_stable", MacroBuiltin::sorry}, {"rustc_const_unstable", MacroBuiltin::sorry}, + {"track_caller", MacroBuiltin::sorry}, /* Derive builtins do not need a real transcriber, but still need one. It should however never be called since builtin derive macros get expanded differently, and benefit from knowing on what kind of items they are diff --git a/gcc/rust/expand/rust-macro-builtins.h b/gcc/rust/expand/rust-macro-builtins.h index 6a9b31c..541e956 100644 --- a/gcc/rust/expand/rust-macro-builtins.h +++ b/gcc/rust/expand/rust-macro-builtins.h @@ -159,6 +159,10 @@ public: AST::MacroInvocData &invoc, AST::InvocKind semicolon); + static tl::optional<AST::Fragment> + option_env_handler (location_t invoc_locus, AST::MacroInvocData &invoc, + AST::InvocKind semicolon); + static tl::optional<AST::Fragment> cfg_handler (location_t invoc_locus, AST::MacroInvocData &invoc, AST::InvocKind semicolon); @@ -177,6 +181,10 @@ public: AST::AsmKind is_global_asm); static tl::optional<AST::Fragment> + llvm_asm_handler (location_t invoc_locus, AST::MacroInvocData &invoc, + AST::InvocKind semicolon, AST::AsmKind is_global_asm); + + static tl::optional<AST::Fragment> format_args_handler (location_t invoc_locus, AST::MacroInvocData &invoc, AST::InvocKind semicolon, AST::FormatArgs::Newline nl); diff --git a/gcc/rust/expand/rust-macro-expand.cc b/gcc/rust/expand/rust-macro-expand.cc index 4d9cade..673b8fb 100644 --- a/gcc/rust/expand/rust-macro-expand.cc +++ b/gcc/rust/expand/rust-macro-expand.cc @@ -23,11 +23,12 @@ #include "rust-ast-full.h" #include "rust-ast-visitor.h" #include "rust-diagnostics.h" +#include "rust-macro.h" #include "rust-parse.h" #include "rust-cfg-strip.h" #include "rust-early-name-resolver.h" -#include "rust-session-manager.h" #include "rust-proc-macro.h" +#include "rust-token-tree-desugar.h" namespace Rust { @@ -78,7 +79,10 @@ MacroExpander::expand_decl_macro (location_t invoc_locus, * trees. */ - AST::DelimTokenTree &invoc_token_tree = invoc.get_delim_tok_tree (); + AST::DelimTokenTree &invoc_token_tree_sugar = invoc.get_delim_tok_tree (); + + // We must first desugar doc comments into proper attributes + auto invoc_token_tree = AST::TokenTreeDesugar ().go (invoc_token_tree_sugar); // find matching arm AST::MacroRule *matched_rule = nullptr; @@ -119,7 +123,7 @@ MacroExpander::expand_decl_macro (location_t invoc_locus, for (auto &ent : matched_fragments) matched_fragments_ptr.emplace (ent.first, ent.second.get ()); - return transcribe_rule (*matched_rule, invoc_token_tree, + return transcribe_rule (rules_def, *matched_rule, invoc_token_tree, matched_fragments_ptr, semicolon, peek_context ()); } @@ -250,7 +254,12 @@ MacroExpander::expand_invoc (AST::MacroInvocation &invoc, } if (invoc.get_kind () == AST::MacroInvocation::InvocKind::Builtin) - expand_eager_invocations (invoc); + { + // Eager expansions are always expressions + push_context (ContextType::EXPR); + expand_eager_invocations (invoc); + pop_context (); + } AST::MacroInvocData &invoc_data = invoc.get_invoc_data (); @@ -616,9 +625,10 @@ MacroExpander::match_n_matches (Parser<MacroInvocLexer> &parser, // matched fragment get the offset in the token stream size_t offs_end = source.get_offs (); - sub_stack.insert_metavar ( - MatchedFragment (fragment->get_ident ().as_string (), - offs_begin, offs_end)); + if (valid_current_match) + sub_stack.insert_metavar ( + MatchedFragment (fragment->get_ident ().as_string (), + offs_begin, offs_end)); } break; @@ -645,15 +655,15 @@ MacroExpander::match_n_matches (Parser<MacroInvocLexer> &parser, } auto old_stack = sub_stack.pop (); - // nest metavars into repetitions - for (auto &ent : old_stack) - sub_stack.append_fragment (ent.first, std::move (ent.second)); - // If we've encountered an error once, stop trying to match more // repetitions if (!valid_current_match) break; + // nest metavars into repetitions + for (auto &ent : old_stack) + sub_stack.append_fragment (ent.first, std::move (ent.second)); + match_amount++; // Break early if we notice there's too many expressions already @@ -1019,7 +1029,8 @@ tokens_to_str (std::vector<std::unique_ptr<AST::Token>> &tokens) AST::Fragment MacroExpander::transcribe_rule ( - AST::MacroRule &match_rule, AST::DelimTokenTree &invoc_token_tree, + AST::MacroRulesDefinition &definition, AST::MacroRule &match_rule, + AST::DelimTokenTree &invoc_token_tree, std::map<std::string, MatchedFragmentContainer *> &matched_fragments, AST::InvocKind invoc_kind, ContextType ctx) { @@ -1033,8 +1044,8 @@ MacroExpander::transcribe_rule ( auto invoc_stream = invoc_token_tree.to_token_stream (); auto macro_rule_tokens = transcribe_tree.to_token_stream (); - auto substitute_context - = SubstituteCtx (invoc_stream, macro_rule_tokens, matched_fragments); + auto substitute_context = SubstituteCtx (invoc_stream, macro_rule_tokens, + matched_fragments, definition); std::vector<std::unique_ptr<AST::Token>> substituted_tokens = substitute_context.substitute_tokens (); diff --git a/gcc/rust/expand/rust-macro-expand.h b/gcc/rust/expand/rust-macro-expand.h index 5e12790..360294c 100644 --- a/gcc/rust/expand/rust-macro-expand.h +++ b/gcc/rust/expand/rust-macro-expand.h @@ -331,7 +331,8 @@ struct MacroExpander AST::DelimTokenTree &invoc_token_tree); AST::Fragment transcribe_rule ( - AST::MacroRule &match_rule, AST::DelimTokenTree &invoc_token_tree, + AST::MacroRulesDefinition &definition, AST::MacroRule &match_rule, + AST::DelimTokenTree &invoc_token_tree, std::map<std::string, MatchedFragmentContainer *> &matched_fragments, AST::InvocKind invoc_kind, ContextType ctx); diff --git a/gcc/rust/expand/rust-macro-substitute-ctx.cc b/gcc/rust/expand/rust-macro-substitute-ctx.cc index a06f831..02e4e3b 100644 --- a/gcc/rust/expand/rust-macro-substitute-ctx.cc +++ b/gcc/rust/expand/rust-macro-substitute-ctx.cc @@ -17,10 +17,47 @@ // <http://www.gnu.org/licenses/>. #include "rust-macro-substitute-ctx.h" +#include "input.h" +#include "rust-hir-map.h" +#include "rust-token.h" namespace Rust { bool +SubstituteCtx::substitute_dollar_crate ( + std::vector<std::unique_ptr<AST::Token>> &expanded) +{ + auto &mappings = Analysis::Mappings::get (); + + auto def_crate = mappings.lookup_macro_def_crate (definition.get_node_id ()); + auto current_crate = mappings.get_current_crate (); + + rust_assert (def_crate); + + // If we're expanding a macro defined in the current crate which uses $crate, + // we can just replace the metavar with the `crate` path segment. Otherwise, + // use the fully qualified extern-crate lookup path `::<crate_name>` + if (*def_crate == current_crate) + { + expanded.push_back (std::make_unique<AST::Token> ( + Rust::Token::make_identifier (UNKNOWN_LOCATION, "crate"))); + } + else + { + auto name = mappings.get_crate_name (*def_crate); + + rust_assert (name); + + expanded.push_back (std::make_unique<AST::Token> ( + Rust::Token::make (SCOPE_RESOLUTION, UNKNOWN_LOCATION))); + expanded.push_back (std::make_unique<AST::Token> ( + Rust::Token::make_identifier (UNKNOWN_LOCATION, std::string (*name)))); + } + + return true; +} + +bool SubstituteCtx::substitute_metavar ( std::unique_ptr<AST::Token> &metavar, std::vector<std::unique_ptr<AST::Token>> &expanded) @@ -30,14 +67,15 @@ SubstituteCtx::substitute_metavar ( auto it = fragments.find (metavar_name); if (it == fragments.end ()) { - // fail to substitute + // fail to substitute, unless we are dealing with a special-case metavar + // like $crate - // HACK: substitute ($ crate) => (crate) - if (metavar->get_id () != CRATE) - return false; + if (metavar->get_id () == CRATE) + return substitute_dollar_crate (expanded); expanded.push_back (metavar->clone_token ()); - return true; + + return false; } else { @@ -187,7 +225,8 @@ SubstituteCtx::substitute_repetition ( kv_match.second->get_fragments ().at (i).get ()); } - auto substitute_context = SubstituteCtx (input, new_macro, sub_map); + auto substitute_context + = SubstituteCtx (input, new_macro, sub_map, definition); auto new_tokens = substitute_context.substitute_tokens (); // Skip the first repetition, but add the separator to the expanded diff --git a/gcc/rust/expand/rust-macro-substitute-ctx.h b/gcc/rust/expand/rust-macro-substitute-ctx.h index e3100a3..c5c4956 100644 --- a/gcc/rust/expand/rust-macro-substitute-ctx.h +++ b/gcc/rust/expand/rust-macro-substitute-ctx.h @@ -18,6 +18,7 @@ #include "rust-ast.h" #include "rust-macro-expand.h" +#include "rust-macro.h" namespace Rust { class SubstituteCtx @@ -25,6 +26,7 @@ class SubstituteCtx std::vector<std::unique_ptr<AST::Token>> &input; std::vector<std::unique_ptr<AST::Token>> ¯o; std::map<std::string, MatchedFragmentContainer *> &fragments; + AST::MacroRulesDefinition &definition; /** * Find the repetition amount to use when expanding a repetition, and @@ -40,11 +42,28 @@ class SubstituteCtx public: SubstituteCtx (std::vector<std::unique_ptr<AST::Token>> &input, std::vector<std::unique_ptr<AST::Token>> ¯o, - std::map<std::string, MatchedFragmentContainer *> &fragments) - : input (input), macro (macro), fragments (fragments) + std::map<std::string, MatchedFragmentContainer *> &fragments, + AST::MacroRulesDefinition &definition) + : input (input), macro (macro), fragments (fragments), + definition (definition) {} /** + * Special-case the $crate metavar to expand to the name of the crate in which + * the macro was defined. + * + * https://doc.rust-lang.org/reference/macros-by-example.html#r-macro.decl.hygiene.crate + * + * + * @param expanded Reference to a vector upon which expanded tokens will be + * pushed + * + * @return True if the substitution succeeded + */ + bool + substitute_dollar_crate (std::vector<std::unique_ptr<AST::Token>> &expanded); + + /** * Substitute a metavariable by its given fragment in a transcribing context, * i.e. replacing $var with the associated fragment. * @@ -52,7 +71,7 @@ public: * @param expanded Reference to a vector upon which expanded tokens will be * pushed * - * @return True iff the substitution succeeded + * @return True if the substitution succeeded */ bool substitute_metavar (std::unique_ptr<AST::Token> &metavar, std::vector<std::unique_ptr<AST::Token>> &expanded); diff --git a/gcc/rust/expand/rust-token-tree-desugar.cc b/gcc/rust/expand/rust-token-tree-desugar.cc new file mode 100644 index 0000000..3b47180 --- /dev/null +++ b/gcc/rust/expand/rust-token-tree-desugar.cc @@ -0,0 +1,72 @@ +// Copyright (C) 2025 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-token-tree-desugar.h" +#include "rust-ast.h" +#include "rust-token.h" + +namespace Rust { +namespace AST { + +DelimTokenTree +TokenTreeDesugar::go (DelimTokenTree &tts) +{ + tts.accept_vis (*this); + + return DelimTokenTree (tts.get_delim_type (), std::move (desugared), + tts.get_locus ()); +} + +void +TokenTreeDesugar::append (TokenPtr &&new_token) +{ + desugared.emplace_back (std::make_unique<Token> (std::move (new_token))); +} + +void +TokenTreeDesugar::append (std::unique_ptr<TokenTree> &&new_token) +{ + desugared.emplace_back (std::move (new_token)); +} + +void +TokenTreeDesugar::visit (Token &tts) +{ + if (tts.get_id () == TokenId::OUTER_DOC_COMMENT + || tts.get_id () == TokenId::INNER_DOC_COMMENT) + { + append (Rust::Token::make (TokenId::HASH, tts.get_locus ())); + + if (tts.get_id () == TokenId::INNER_DOC_COMMENT) + append (Rust::Token::make (EXCLAM, tts.get_locus ())); + + append (Rust::Token::make (TokenId::LEFT_SQUARE, tts.get_locus ())); + append (Rust::Token::make_identifier (tts.get_locus (), "doc")); + append (Rust::Token::make (TokenId::EQUAL, tts.get_locus ())); + append (Rust::Token::make_string (tts.get_locus (), + std::string (tts.get_str ()))); + append (Rust::Token::make (TokenId::RIGHT_SQUARE, tts.get_locus ())); + } + else + { + append (tts.clone_token ()); + } +} + +}; // namespace AST +}; // namespace Rust diff --git a/gcc/rust/expand/rust-token-tree-desugar.h b/gcc/rust/expand/rust-token-tree-desugar.h new file mode 100644 index 0000000..ccba53b --- /dev/null +++ b/gcc/rust/expand/rust-token-tree-desugar.h @@ -0,0 +1,55 @@ +// Copyright (C) 2025 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_TOKEN_TREE_DESUGAR_H +#define RUST_TOKEN_TREE_DESUGAR_H + +#include "rust-ast-visitor.h" +#include "rust-system.h" +#include "rust-ast.h" + +namespace Rust { +namespace AST { + +/** + * Desugar a given token-tree before parsing it for a macro invocation. At the + * moment, the sole purpose of this desugar is to transform doc-comments into + * their attribute form (/// comment -> #[doc = "comment"]) + */ +class TokenTreeDesugar : public DefaultASTVisitor +{ +public: + TokenTreeDesugar () : desugared (std::vector<std::unique_ptr<TokenTree>> ()) + {} + + DelimTokenTree go (DelimTokenTree &tts); + +private: + std::vector<std::unique_ptr<TokenTree>> desugared; + void append (TokenPtr &&new_token); + void append (std::unique_ptr<TokenTree> &&new_token); + + using DefaultASTVisitor::visit; + + virtual void visit (Token &tts) override; +}; + +}; // namespace AST +}; // namespace Rust + +#endif //! RUST_TOKEN_TREE_DESUGAR_H diff --git a/gcc/rust/hir/rust-ast-lower-base.cc b/gcc/rust/hir/rust-ast-lower-base.cc index 906706e..2d9a445 100644 --- a/gcc/rust/hir/rust-ast-lower-base.cc +++ b/gcc/rust/hir/rust-ast-lower-base.cc @@ -23,13 +23,30 @@ #include "rust-ast.h" #include "rust-attribute-values.h" #include "rust-diagnostics.h" +#include "rust-expr.h" #include "rust-item.h" #include "rust-system.h" +#include "rust-attributes.h" namespace Rust { namespace HIR { void +ASTLoweringBase::visit (AST::MacroInvocation &invoc) +{ + rust_fatal_error (invoc.get_locus (), "rogue macro detected during lowering"); + rust_unreachable (); +} + +void +ASTLoweringBase::visit (AST::ErrorPropagationExpr &expr) +{ + rust_fatal_error (expr.get_locus (), + "missing desugar for question mark operator"); + rust_unreachable (); +} + +void ASTLoweringBase::visit (AST::Token &) {} void @@ -107,9 +124,6 @@ void ASTLoweringBase::visit (AST::DereferenceExpr &) {} void -ASTLoweringBase::visit (AST::ErrorPropagationExpr &) -{} -void ASTLoweringBase::visit (AST::NegationExpr &) {} void @@ -253,6 +267,10 @@ void ASTLoweringBase::visit (AST::InlineAsm &) {} +void +ASTLoweringBase::visit (AST::LlvmInlineAsm &) +{} + // void ASTLoweringBase::visit(MatchCasematch_case) {} // void ASTLoweringBase:: (AST::MatchCaseBlockExpr &) {} // void ASTLoweringBase:: (AST::MatchCaseExpr &) {} @@ -372,9 +390,6 @@ void ASTLoweringBase::visit (AST::MacroRulesDefinition &) {} void -ASTLoweringBase::visit (AST::MacroInvocation &) -{} -void ASTLoweringBase::visit (AST::MetaItemPath &) {} void @@ -665,6 +680,7 @@ ASTLoweringBase::lower_self (AST::Param ¶m) Analysis::NodeMapping mapping (crate_num, self.get_node_id (), mappings.get_next_hir_id (crate_num), mappings.get_next_localdef_id (crate_num)); + mappings.insert_location (mapping.get_hirid (), param.get_locus ()); if (self.has_type ()) { @@ -678,8 +694,12 @@ ASTLoweringBase::lower_self (AST::Param ¶m) self.get_is_mut (), self.get_locus ()); } - AST::Lifetime l = self.get_lifetime (); - return HIR::SelfParam (mapping, lower_lifetime (l), self.get_is_mut (), + tl::optional<HIR::Lifetime> lifetime = tl::nullopt; + + if (self.has_lifetime ()) + lifetime = lower_lifetime (self.get_lifetime ()); + + return HIR::SelfParam (mapping, lifetime, self.get_is_mut (), self.get_locus ()); } @@ -745,7 +765,7 @@ ASTLoweringBase::handle_outer_attributes (const ItemWrapper &item) for (const auto &attr : item.get_outer_attrs ()) { const auto &str_path = attr.get_path ().as_string (); - if (!is_known_attribute (str_path)) + if (!Analysis::Attributes::is_known (str_path)) { rust_error_at (attr.get_locus (), "unknown attribute"); continue; @@ -809,13 +829,6 @@ ASTLoweringBase::handle_lang_item_attribute (const ItemWrapper &item, } bool -ASTLoweringBase::is_known_attribute (const std::string &attribute_path) const -{ - const auto &lookup = attr_mappings->lookup_builtin (attribute_path); - return !lookup.is_error (); -} - -bool ASTLoweringBase::attribute_handled_in_another_pass ( const std::string &attribute_path) const { @@ -928,8 +941,8 @@ ASTLoweringBase::lower_literal (const AST::Literal &literal) case AST::Literal::LitType::BYTE_STRING: type = HIR::Literal::LitType::BYTE_STRING; break; - case AST::Literal::LitType::RAW_STRING: // TODO: Lower raw string literals. - rust_unreachable (); + case AST::Literal::LitType::RAW_STRING: + type = HIR::Literal::LitType::STRING; break; case AST::Literal::LitType::INT: type = HIR::Literal::LitType::INT; diff --git a/gcc/rust/hir/rust-ast-lower-base.h b/gcc/rust/hir/rust-ast-lower-base.h index 1bd1343..3116181 100644 --- a/gcc/rust/hir/rust-ast-lower-base.h +++ b/gcc/rust/hir/rust-ast-lower-base.h @@ -60,202 +60,205 @@ class ASTLoweringBase : public AST::ASTVisitor public: virtual ~ASTLoweringBase () {} + // Special casing nodes that should never reach the HIR lowering stage + virtual void visit (AST::MacroInvocation &) override final; + virtual void visit (AST::ErrorPropagationExpr &) override final; + // visitor impl // rust-ast.h // virtual void visit(AttrInput& attr_input); // virtual void visit(TokenTree& token_tree); // virtual void visit(MacroMatch& macro_match); - virtual void visit (AST::Token &tok); - virtual void visit (AST::DelimTokenTree &delim_tok_tree); - virtual void visit (AST::AttrInputMetaItemContainer &input); - // virtual void visit(MetaItem& meta_item); - // void vsit(Stmt& stmt); - // virtual void visit(Expr& expr); - virtual void visit (AST::IdentifierExpr &ident_expr); - // virtual void visit(Pattern& pattern); - // virtual void visit(Type& type); - // virtual void visit(TypeParamBound& type_param_bound); - virtual void visit (AST::Lifetime &lifetime); - // virtual void visit(GenericParam& generic_param); - virtual void visit (AST::LifetimeParam &lifetime_param); - virtual void visit (AST::ConstGenericParam &const_param); - // virtual void visit(TraitItem& trait_item); - // virtual void visit(InherentImplItem& inherent_impl_item); - // virtual void visit(TraitImplItem& trait_impl_item); + virtual void visit (AST::Token &tok) override; + virtual void visit (AST::DelimTokenTree &delim_tok_tree) override; + virtual void visit (AST::AttrInputMetaItemContainer &input) override; + // virtual void visit(MetaItem& meta_item) override; + // void vsit(Stmt& stmt) override; + // virtual void visit(Expr& expr) override; + virtual void visit (AST::IdentifierExpr &ident_expr) override; + // virtual void visit(Pattern& pattern) override; + // virtual void visit(Type& type) override; + // virtual void visit(TypeParamBound& type_param_bound) override; + virtual void visit (AST::Lifetime &lifetime) override; + // virtual void visit(GenericParam& generic_param) override; + virtual void visit (AST::LifetimeParam &lifetime_param) override; + virtual void visit (AST::ConstGenericParam &const_param) override; + // virtual void visit(TraitItem& trait_item) override; + // virtual void visit(InherentImplItem& inherent_impl_item) override; + // virtual void visit(TraitImplItem& trait_impl_item) override; // rust-path.h - virtual void visit (AST::PathInExpression &path); - virtual void visit (AST::TypePathSegment &segment); - virtual void visit (AST::TypePathSegmentGeneric &segment); - virtual void visit (AST::TypePathSegmentFunction &segment); - virtual void visit (AST::TypePath &path); - virtual void visit (AST::QualifiedPathInExpression &path); - virtual void visit (AST::QualifiedPathInType &path); + virtual void visit (AST::PathInExpression &path) override; + virtual void visit (AST::TypePathSegment &segment) override; + virtual void visit (AST::TypePathSegmentGeneric &segment) override; + virtual void visit (AST::TypePathSegmentFunction &segment) override; + virtual void visit (AST::TypePath &path) override; + virtual void visit (AST::QualifiedPathInExpression &path) override; + virtual void visit (AST::QualifiedPathInType &path) override; // rust-expr.h - virtual void visit (AST::LiteralExpr &expr); - virtual void visit (AST::AttrInputLiteral &attr_input); - virtual void visit (AST::AttrInputMacro &attr_input); - virtual void visit (AST::MetaItemLitExpr &meta_item); - virtual void visit (AST::MetaItemPathLit &meta_item); - virtual void visit (AST::BorrowExpr &expr); - virtual void visit (AST::DereferenceExpr &expr); - virtual void visit (AST::ErrorPropagationExpr &expr); - virtual void visit (AST::NegationExpr &expr); - virtual void visit (AST::ArithmeticOrLogicalExpr &expr); - virtual void visit (AST::ComparisonExpr &expr); - virtual void visit (AST::LazyBooleanExpr &expr); - virtual void visit (AST::TypeCastExpr &expr); - virtual void visit (AST::AssignmentExpr &expr); - virtual void visit (AST::CompoundAssignmentExpr &expr); - virtual void visit (AST::GroupedExpr &expr); - // virtual void visit(ArrayElems& elems); - virtual void visit (AST::ArrayElemsValues &elems); - virtual void visit (AST::ArrayElemsCopied &elems); - virtual void visit (AST::ArrayExpr &expr); - virtual void visit (AST::ArrayIndexExpr &expr); - virtual void visit (AST::TupleExpr &expr); - virtual void visit (AST::TupleIndexExpr &expr); - virtual void visit (AST::StructExprStruct &expr); - // virtual void visit(StructExprField& field); - virtual void visit (AST::StructExprFieldIdentifier &field); - virtual void visit (AST::StructExprFieldIdentifierValue &field); - virtual void visit (AST::StructExprFieldIndexValue &field); - virtual void visit (AST::StructExprStructFields &expr); - virtual void visit (AST::StructExprStructBase &expr); - virtual void visit (AST::CallExpr &expr); - virtual void visit (AST::MethodCallExpr &expr); - virtual void visit (AST::FieldAccessExpr &expr); - virtual void visit (AST::ClosureExprInner &expr); - virtual void visit (AST::BlockExpr &expr); - virtual void visit (AST::ClosureExprInnerTyped &expr); - virtual void visit (AST::ContinueExpr &expr); - virtual void visit (AST::BreakExpr &expr); - virtual void visit (AST::RangeFromToExpr &expr); - virtual void visit (AST::RangeFromExpr &expr); - virtual void visit (AST::RangeToExpr &expr); - virtual void visit (AST::RangeFullExpr &expr); - virtual void visit (AST::RangeFromToInclExpr &expr); - virtual void visit (AST::RangeToInclExpr &expr); - virtual void visit (AST::BoxExpr &expr); - virtual void visit (AST::ReturnExpr &expr); - virtual void visit (AST::UnsafeBlockExpr &expr); - virtual void visit (AST::LoopExpr &expr); - virtual void visit (AST::WhileLoopExpr &expr); - virtual void visit (AST::WhileLetLoopExpr &expr); - virtual void visit (AST::ForLoopExpr &expr); - virtual void visit (AST::IfExpr &expr); - virtual void visit (AST::IfExprConseqElse &expr); - virtual void visit (AST::IfLetExpr &expr); - virtual void visit (AST::IfLetExprConseqElse &expr); - virtual void visit (AST::InlineAsm &expr); - // virtual void visit(MatchCase& match_case); - // virtual void visit (AST::MatchCaseBlockExpr &match_case); - // virtual void visit (AST::MatchCaseExpr &match_case); - virtual void visit (AST::MatchExpr &expr); - virtual void visit (AST::AwaitExpr &expr); - virtual void visit (AST::AsyncBlockExpr &expr); + virtual void visit (AST::LiteralExpr &expr) override; + virtual void visit (AST::AttrInputLiteral &attr_input) override; + virtual void visit (AST::AttrInputMacro &attr_input) override; + virtual void visit (AST::MetaItemLitExpr &meta_item) override; + virtual void visit (AST::MetaItemPathLit &meta_item) override; + virtual void visit (AST::BorrowExpr &expr) override; + virtual void visit (AST::DereferenceExpr &expr) override; + virtual void visit (AST::NegationExpr &expr) override; + virtual void visit (AST::ArithmeticOrLogicalExpr &expr) override; + virtual void visit (AST::ComparisonExpr &expr) override; + virtual void visit (AST::LazyBooleanExpr &expr) override; + virtual void visit (AST::TypeCastExpr &expr) override; + virtual void visit (AST::AssignmentExpr &expr) override; + virtual void visit (AST::CompoundAssignmentExpr &expr) override; + virtual void visit (AST::GroupedExpr &expr) override; + // virtual void visit(ArrayElems& elems) override; + virtual void visit (AST::ArrayElemsValues &elems) override; + virtual void visit (AST::ArrayElemsCopied &elems) override; + virtual void visit (AST::ArrayExpr &expr) override; + virtual void visit (AST::ArrayIndexExpr &expr) override; + virtual void visit (AST::TupleExpr &expr) override; + virtual void visit (AST::TupleIndexExpr &expr) override; + virtual void visit (AST::StructExprStruct &expr) override; + // virtual void visit(StructExprField& field) override; + virtual void visit (AST::StructExprFieldIdentifier &field) override; + virtual void visit (AST::StructExprFieldIdentifierValue &field) override; + virtual void visit (AST::StructExprFieldIndexValue &field) override; + virtual void visit (AST::StructExprStructFields &expr) override; + virtual void visit (AST::StructExprStructBase &expr) override; + virtual void visit (AST::CallExpr &expr) override; + virtual void visit (AST::MethodCallExpr &expr) override; + virtual void visit (AST::FieldAccessExpr &expr) override; + virtual void visit (AST::ClosureExprInner &expr) override; + virtual void visit (AST::BlockExpr &expr) override; + virtual void visit (AST::ClosureExprInnerTyped &expr) override; + virtual void visit (AST::ContinueExpr &expr) override; + virtual void visit (AST::BreakExpr &expr) override; + virtual void visit (AST::RangeFromToExpr &expr) override; + virtual void visit (AST::RangeFromExpr &expr) override; + virtual void visit (AST::RangeToExpr &expr) override; + virtual void visit (AST::RangeFullExpr &expr) override; + virtual void visit (AST::RangeFromToInclExpr &expr) override; + virtual void visit (AST::RangeToInclExpr &expr) override; + virtual void visit (AST::BoxExpr &expr) override; + virtual void visit (AST::ReturnExpr &expr) override; + virtual void visit (AST::UnsafeBlockExpr &expr) override; + virtual void visit (AST::LoopExpr &expr) override; + virtual void visit (AST::WhileLoopExpr &expr) override; + virtual void visit (AST::WhileLetLoopExpr &expr) override; + virtual void visit (AST::ForLoopExpr &expr) override; + virtual void visit (AST::IfExpr &expr) override; + virtual void visit (AST::IfExprConseqElse &expr) override; + virtual void visit (AST::IfLetExpr &expr) override; + virtual void visit (AST::IfLetExprConseqElse &expr) override; + virtual void visit (AST::InlineAsm &expr) override; + virtual void visit (AST::LlvmInlineAsm &expr) override; + // virtual void visit(MatchCase& match_case) override; + // virtual void visit (AST::MatchCaseBlockExpr &match_case) override; + // virtual void visit (AST::MatchCaseExpr &match_case) override; + virtual void visit (AST::MatchExpr &expr) override; + virtual void visit (AST::AwaitExpr &expr) override; + virtual void visit (AST::AsyncBlockExpr &expr) override; // rust-item.h - virtual void visit (AST::TypeParam ¶m); - // virtual void visit(WhereClauseItem& item); - virtual void visit (AST::LifetimeWhereClauseItem &item); - virtual void visit (AST::TypeBoundWhereClauseItem &item); - virtual void visit (AST::Module &module); - virtual void visit (AST::ExternCrate &crate); - // virtual void visit(UseTree& use_tree); - virtual void visit (AST::UseTreeGlob &use_tree); - virtual void visit (AST::UseTreeList &use_tree); - virtual void visit (AST::UseTreeRebind &use_tree); - virtual void visit (AST::UseDeclaration &use_decl); - virtual void visit (AST::Function &function); - virtual void visit (AST::TypeAlias &type_alias); - virtual void visit (AST::StructStruct &struct_item); - virtual void visit (AST::TupleStruct &tuple_struct); - virtual void visit (AST::EnumItem &item); - virtual void visit (AST::EnumItemTuple &item); - virtual void visit (AST::EnumItemStruct &item); - virtual void visit (AST::EnumItemDiscriminant &item); - virtual void visit (AST::Enum &enum_item); - virtual void visit (AST::Union &union_item); - virtual void visit (AST::ConstantItem &const_item); - virtual void visit (AST::StaticItem &static_item); - virtual void visit (AST::TraitItemConst &item); - virtual void visit (AST::TraitItemType &item); - virtual void visit (AST::Trait &trait); - virtual void visit (AST::InherentImpl &impl); - virtual void visit (AST::TraitImpl &impl); - // virtual void visit(ExternalItem& item); - virtual void visit (AST::ExternalTypeItem &item); - virtual void visit (AST::ExternalStaticItem &item); - virtual void visit (AST::ExternBlock &block); + virtual void visit (AST::TypeParam ¶m) override; + // virtual void visit(WhereClauseItem& item) override; + virtual void visit (AST::LifetimeWhereClauseItem &item) override; + virtual void visit (AST::TypeBoundWhereClauseItem &item) override; + virtual void visit (AST::Module &module) override; + virtual void visit (AST::ExternCrate &crate) override; + // virtual void visit(UseTree& use_tree) override; + virtual void visit (AST::UseTreeGlob &use_tree) override; + virtual void visit (AST::UseTreeList &use_tree) override; + virtual void visit (AST::UseTreeRebind &use_tree) override; + virtual void visit (AST::UseDeclaration &use_decl) override; + virtual void visit (AST::Function &function) override; + virtual void visit (AST::TypeAlias &type_alias) override; + virtual void visit (AST::StructStruct &struct_item) override; + virtual void visit (AST::TupleStruct &tuple_struct) override; + virtual void visit (AST::EnumItem &item) override; + virtual void visit (AST::EnumItemTuple &item) override; + virtual void visit (AST::EnumItemStruct &item) override; + virtual void visit (AST::EnumItemDiscriminant &item) override; + virtual void visit (AST::Enum &enum_item) override; + virtual void visit (AST::Union &union_item) override; + virtual void visit (AST::ConstantItem &const_item) override; + virtual void visit (AST::StaticItem &static_item) override; + virtual void visit (AST::TraitItemConst &item) override; + virtual void visit (AST::TraitItemType &item) override; + virtual void visit (AST::Trait &trait) override; + virtual void visit (AST::InherentImpl &impl) override; + virtual void visit (AST::TraitImpl &impl) override; + // virtual void visit(ExternalItem& item) override; + virtual void visit (AST::ExternalTypeItem &item) override; + virtual void visit (AST::ExternalStaticItem &item) override; + virtual void visit (AST::ExternBlock &block) override; // rust-macro.h - virtual void visit (AST::MacroMatchFragment &match); - virtual void visit (AST::MacroMatchRepetition &match); - virtual void visit (AST::MacroMatcher &matcher); - virtual void visit (AST::MacroRulesDefinition &rules_def); - virtual void visit (AST::MacroInvocation ¯o_invoc); - virtual void visit (AST::MetaItemPath &meta_item); - virtual void visit (AST::MetaItemSeq &meta_item); - virtual void visit (AST::MetaWord &meta_item); - virtual void visit (AST::MetaNameValueStr &meta_item); - virtual void visit (AST::MetaListPaths &meta_item); - virtual void visit (AST::MetaListNameValueStr &meta_item); + virtual void visit (AST::MacroMatchFragment &match) override; + virtual void visit (AST::MacroMatchRepetition &match) override; + virtual void visit (AST::MacroMatcher &matcher) override; + virtual void visit (AST::MacroRulesDefinition &rules_def) override; + virtual void visit (AST::MetaItemPath &meta_item) override; + virtual void visit (AST::MetaItemSeq &meta_item) override; + virtual void visit (AST::MetaWord &meta_item) override; + virtual void visit (AST::MetaNameValueStr &meta_item) override; + virtual void visit (AST::MetaListPaths &meta_item) override; + virtual void visit (AST::MetaListNameValueStr &meta_item) override; // rust-pattern.h - virtual void visit (AST::LiteralPattern &pattern); - virtual void visit (AST::IdentifierPattern &pattern); - virtual void visit (AST::WildcardPattern &pattern); - virtual void visit (AST::RestPattern &pattern); - // virtual void visit(RangePatternBound& bound); - virtual void visit (AST::RangePatternBoundLiteral &bound); - virtual void visit (AST::RangePatternBoundPath &bound); - virtual void visit (AST::RangePatternBoundQualPath &bound); - virtual void visit (AST::RangePattern &pattern); - virtual void visit (AST::ReferencePattern &pattern); - // virtual void visit(StructPatternField& field); - virtual void visit (AST::StructPatternFieldTuplePat &field); - virtual void visit (AST::StructPatternFieldIdentPat &field); - virtual void visit (AST::StructPatternFieldIdent &field); - virtual void visit (AST::StructPattern &pattern); - // virtual void visit(TupleStructItems& tuple_items); - virtual void visit (AST::TupleStructItemsNoRange &tuple_items); - virtual void visit (AST::TupleStructItemsRange &tuple_items); - virtual void visit (AST::TupleStructPattern &pattern); - // virtual void visit(TuplePatternItems& tuple_items); - virtual void visit (AST::TuplePatternItemsMultiple &tuple_items); - virtual void visit (AST::TuplePatternItemsRanged &tuple_items); - virtual void visit (AST::TuplePattern &pattern); - virtual void visit (AST::GroupedPattern &pattern); - virtual void visit (AST::SlicePattern &pattern); - virtual void visit (AST::AltPattern &pattern); + virtual void visit (AST::LiteralPattern &pattern) override; + virtual void visit (AST::IdentifierPattern &pattern) override; + virtual void visit (AST::WildcardPattern &pattern) override; + virtual void visit (AST::RestPattern &pattern) override; + // virtual void visit(RangePatternBound& bound) override; + virtual void visit (AST::RangePatternBoundLiteral &bound) override; + virtual void visit (AST::RangePatternBoundPath &bound) override; + virtual void visit (AST::RangePatternBoundQualPath &bound) override; + virtual void visit (AST::RangePattern &pattern) override; + virtual void visit (AST::ReferencePattern &pattern) override; + // virtual void visit(StructPatternField& field) override; + virtual void visit (AST::StructPatternFieldTuplePat &field) override; + virtual void visit (AST::StructPatternFieldIdentPat &field) override; + virtual void visit (AST::StructPatternFieldIdent &field) override; + virtual void visit (AST::StructPattern &pattern) override; + // virtual void visit(TupleStructItems& tuple_items) override; + virtual void visit (AST::TupleStructItemsNoRange &tuple_items) override; + virtual void visit (AST::TupleStructItemsRange &tuple_items) override; + virtual void visit (AST::TupleStructPattern &pattern) override; + // virtual void visit(TuplePatternItems& tuple_items) override; + virtual void visit (AST::TuplePatternItemsMultiple &tuple_items) override; + virtual void visit (AST::TuplePatternItemsRanged &tuple_items) override; + virtual void visit (AST::TuplePattern &pattern) override; + virtual void visit (AST::GroupedPattern &pattern) override; + virtual void visit (AST::SlicePattern &pattern) override; + virtual void visit (AST::AltPattern &pattern) override; // rust-stmt.h - virtual void visit (AST::EmptyStmt &stmt); - virtual void visit (AST::LetStmt &stmt); - virtual void visit (AST::ExprStmt &stmt); + virtual void visit (AST::EmptyStmt &stmt) override; + virtual void visit (AST::LetStmt &stmt) override; + virtual void visit (AST::ExprStmt &stmt) override; // rust-type.h - virtual void visit (AST::TraitBound &bound); - virtual void visit (AST::ImplTraitType &type); - virtual void visit (AST::TraitObjectType &type); - virtual void visit (AST::ParenthesisedType &type); - virtual void visit (AST::ImplTraitTypeOneBound &type); - virtual void visit (AST::TraitObjectTypeOneBound &type); - virtual void visit (AST::TupleType &type); - virtual void visit (AST::NeverType &type); - virtual void visit (AST::RawPointerType &type); - virtual void visit (AST::ReferenceType &type); - virtual void visit (AST::ArrayType &type); - virtual void visit (AST::SliceType &type); - virtual void visit (AST::InferredType &type); - virtual void visit (AST::BareFunctionType &type); - virtual void visit (AST::FunctionParam ¶m); - virtual void visit (AST::VariadicParam ¶m); - virtual void visit (AST::SelfParam ¶m); - - virtual void visit (AST::FormatArgs &fmt); + virtual void visit (AST::TraitBound &bound) override; + virtual void visit (AST::ImplTraitType &type) override; + virtual void visit (AST::TraitObjectType &type) override; + virtual void visit (AST::ParenthesisedType &type) override; + virtual void visit (AST::ImplTraitTypeOneBound &type) override; + virtual void visit (AST::TraitObjectTypeOneBound &type) override; + virtual void visit (AST::TupleType &type) override; + virtual void visit (AST::NeverType &type) override; + virtual void visit (AST::RawPointerType &type) override; + virtual void visit (AST::ReferenceType &type) override; + virtual void visit (AST::ArrayType &type) override; + virtual void visit (AST::SliceType &type) override; + virtual void visit (AST::InferredType &type) override; + virtual void visit (AST::BareFunctionType &type) override; + virtual void visit (AST::FunctionParam ¶m) override; + virtual void visit (AST::VariadicParam ¶m) override; + virtual void visit (AST::SelfParam ¶m) override; + + virtual void visit (AST::FormatArgs &fmt) override; protected: ASTLoweringBase () diff --git a/gcc/rust/hir/rust-ast-lower-block.h b/gcc/rust/hir/rust-ast-lower-block.h index be6ca64..93cd443 100644 --- a/gcc/rust/hir/rust-ast-lower-block.h +++ b/gcc/rust/hir/rust-ast-lower-block.h @@ -115,7 +115,7 @@ class ASTLoweringIfLetBlock : public ASTLoweringBase using Rust::HIR::ASTLoweringBase::visit; public: - static HIR::IfLetExpr *translate (AST::IfLetExpr &expr) + static HIR::MatchExpr *translate (AST::IfLetExpr &expr) { ASTLoweringIfLetBlock resolver; expr.accept_vis (resolver); @@ -135,7 +135,10 @@ public: private: ASTLoweringIfLetBlock () : ASTLoweringBase (), translated (nullptr) {} - HIR::IfLetExpr *translated; + void desugar_iflet (AST::IfLetExpr &, HIR::Expr **, HIR::Expr *, + std::vector<HIR::MatchCase> &); + + HIR::MatchExpr *translated; }; class ASTLoweringExprWithBlock : public ASTLoweringBase @@ -149,9 +152,7 @@ public: ASTLoweringExprWithBlock resolver; expr.accept_vis (resolver); if (resolver.translated != nullptr) - { - resolver.mappings.insert_hir_expr (resolver.translated); - } + resolver.mappings.insert_hir_expr (resolver.translated); *terminated = resolver.terminated; return resolver.translated; @@ -194,7 +195,9 @@ public: HIR::BlockExpr *loop_block = ASTLoweringBlock::translate (expr.get_loop_block (), &terminated); - HIR::LoopLabel loop_label = lower_loop_label (expr.get_loop_label ()); + tl::optional<HIR::LoopLabel> loop_label = tl::nullopt; + if (expr.has_loop_label ()) + loop_label = lower_loop_label (expr.get_loop_label ()); auto crate_num = mappings.get_current_crate (); Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), diff --git a/gcc/rust/hir/rust-ast-lower-expr.cc b/gcc/rust/hir/rust-ast-lower-expr.cc index be7ff41..07d0c835 100644 --- a/gcc/rust/hir/rust-ast-lower-expr.cc +++ b/gcc/rust/hir/rust-ast-lower-expr.cc @@ -17,6 +17,7 @@ // <http://www.gnu.org/licenses/>. #include "rust-ast-lower-expr.h" +#include "optional.h" #include "rust-ast-lower-base.h" #include "rust-ast-lower-block.h" #include "rust-ast-lower-struct-field-expr.h" @@ -25,6 +26,7 @@ #include "rust-ast.h" #include "rust-diagnostics.h" #include "rust-system.h" +#include "tree/rust-hir-expr.h" namespace Rust { namespace HIR { @@ -76,7 +78,7 @@ ASTLoweringExpr::visit (AST::TupleIndexExpr &expr) void ASTLoweringExpr::visit (AST::TupleExpr &expr) { - std::vector<std::unique_ptr<HIR::Expr> > tuple_elements; + std::vector<std::unique_ptr<HIR::Expr>> tuple_elements; for (auto &e : expr.get_tuple_elems ()) { HIR::Expr *t = ASTLoweringExpr::translate (*e); @@ -173,7 +175,7 @@ ASTLoweringExpr::visit (AST::CallExpr &expr) HIR::Expr *func = ASTLoweringExpr::translate (expr.get_function_expr ()); auto const &in_params = expr.get_params (); - std::vector<std::unique_ptr<HIR::Expr> > params; + std::vector<std::unique_ptr<HIR::Expr>> params; for (auto ¶m : in_params) { auto trans = ASTLoweringExpr::translate (*param); @@ -199,7 +201,7 @@ ASTLoweringExpr::visit (AST::MethodCallExpr &expr) HIR::Expr *receiver = ASTLoweringExpr::translate (expr.get_receiver_expr ()); auto const &in_params = expr.get_params (); - std::vector<std::unique_ptr<HIR::Expr> > params; + std::vector<std::unique_ptr<HIR::Expr>> params; for (auto ¶m : in_params) { auto trans = ASTLoweringExpr::translate (*param); @@ -289,7 +291,7 @@ ASTLoweringExpr::visit (AST::ArrayIndexExpr &expr) void ASTLoweringExpr::visit (AST::ArrayElemsValues &elems) { - std::vector<std::unique_ptr<HIR::Expr> > elements; + std::vector<std::unique_ptr<HIR::Expr>> elements; for (auto &elem : elems.get_values ()) { HIR::Expr *translated_elem = ASTLoweringExpr::translate (*elem); @@ -510,16 +512,18 @@ ASTLoweringExpr::visit (AST::StructExprStructFields &struct_expr) HIR::PathInExpression copied_path (*path); delete path; - HIR::StructBase *base = nullptr; + tl::optional<std::unique_ptr<HIR::StructBase>> base = tl::nullopt; if (struct_expr.has_struct_base ()) { HIR::Expr *translated_base = ASTLoweringExpr::translate ( struct_expr.get_struct_base ().get_base_struct ()); - base = new HIR::StructBase (std::unique_ptr<HIR::Expr> (translated_base)); + base = tl::optional<std::unique_ptr<HIR::StructBase>> ( + std::make_unique<StructBase> ( + std::unique_ptr<HIR::Expr> (translated_base))); } auto const &in_fields = struct_expr.get_fields (); - std::vector<std::unique_ptr<HIR::StructExprField> > fields; + std::vector<std::unique_ptr<HIR::StructExprField>> fields; for (auto &field : in_fields) { HIR::StructExprField *translated @@ -534,7 +538,8 @@ ASTLoweringExpr::visit (AST::StructExprStructFields &struct_expr) translated = new HIR::StructExprStructFields (mapping, copied_path, std::move (fields), - struct_expr.get_locus (), base, + struct_expr.get_locus (), + std::move (base), struct_expr.get_inner_attrs (), struct_expr.get_outer_attrs ()); } @@ -586,14 +591,16 @@ ASTLoweringExpr::visit (AST::WhileLoopExpr &expr) void ASTLoweringExpr::visit (AST::ForLoopExpr &expr) { - translated = ASTLoweringExprWithBlock::translate (expr, &terminated); + rust_unreachable (); } void ASTLoweringExpr::visit (AST::BreakExpr &expr) { - HIR::Lifetime break_label - = lower_lifetime (expr.get_label ().get_lifetime ()); + tl::optional<HIR::Lifetime> break_label = tl::nullopt; + if (expr.has_label ()) + break_label = lower_lifetime (expr.get_label_unchecked ().get_lifetime ()); + HIR::Expr *break_expr = expr.has_break_expr () ? ASTLoweringExpr::translate (expr.get_break_expr ()) @@ -613,7 +620,9 @@ ASTLoweringExpr::visit (AST::BreakExpr &expr) void ASTLoweringExpr::visit (AST::ContinueExpr &expr) { - HIR::Lifetime break_label = lower_lifetime (expr.get_label ()); + tl::optional<HIR::Lifetime> break_label; + if (expr.has_label ()) + break_label = lower_lifetime (expr.get_label_unchecked ()); auto crate_num = mappings.get_current_crate (); Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), @@ -628,9 +637,6 @@ ASTLoweringExpr::visit (AST::ContinueExpr &expr) void ASTLoweringExpr::visit (AST::BorrowExpr &expr) { - if (expr.is_raw_borrow ()) - rust_unreachable (); - HIR::Expr *borrow_lvalue = ASTLoweringExpr::translate (expr.get_borrowed_expr ()); @@ -641,8 +647,8 @@ ASTLoweringExpr::visit (AST::BorrowExpr &expr) auto *borrow_expr = new HIR::BorrowExpr (mapping, std::unique_ptr<HIR::Expr> (borrow_lvalue), - expr.get_mutability (), expr.get_outer_attrs (), - expr.get_locus ()); + expr.get_mutability (), expr.is_raw_borrow (), + expr.get_outer_attrs (), expr.get_locus ()); if (expr.get_is_double_borrow ()) { @@ -654,8 +660,8 @@ ASTLoweringExpr::visit (AST::BorrowExpr &expr) borrow_expr = new HIR::BorrowExpr (mapping, std::unique_ptr<HIR::Expr> (borrow_expr), - expr.get_mutability (), expr.get_outer_attrs (), - expr.get_locus ()); + expr.get_mutability (), expr.is_raw_borrow (), + expr.get_outer_attrs (), expr.get_locus ()); } translated = borrow_expr; @@ -679,21 +685,6 @@ ASTLoweringExpr::visit (AST::DereferenceExpr &expr) } void -ASTLoweringExpr::visit (AST::ErrorPropagationExpr &expr) -{ - HIR::Expr *propagating_expr - = ASTLoweringExpr::translate (expr.get_propagating_expr ()); - - auto crate_num = mappings.get_current_crate (); - Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), - mappings.get_next_hir_id (crate_num), - UNKNOWN_LOCAL_DEFID); - translated = new HIR::ErrorPropagationExpr ( - mapping, std::unique_ptr<HIR::Expr> (propagating_expr), - expr.get_outer_attrs (), expr.get_locus ()); -} - -void ASTLoweringExpr::visit (AST::MatchExpr &expr) { translated = ASTLoweringExprWithBlock::translate (expr, &terminated); @@ -829,6 +820,115 @@ ASTLoweringExpr::visit (AST::ClosureExprInnerTyped &expr) expr.get_locus ()); } +HIR::InlineAsmOperand +translate_operand_in (const AST::InlineAsmOperand &operand) +{ + auto in_value = operand.get_in (); + + struct HIR::InlineAsmOperand::In in ( + in_value.reg, + std::unique_ptr<Expr> (ASTLoweringExpr::translate (*in_value.expr.get ()))); + return in; +} + +HIR::InlineAsmOperand +translate_operand_out (const AST::InlineAsmOperand &operand) +{ + auto out_value = operand.get_out (); + struct HIR::InlineAsmOperand::Out out (out_value.reg, out_value.late, + std::unique_ptr<Expr> ( + ASTLoweringExpr::translate ( + *out_value.expr.get ()))); + return out; +} +HIR::InlineAsmOperand +translate_operand_inout (const AST::InlineAsmOperand &operand) +{ + auto inout_value = operand.get_in_out (); + struct HIR::InlineAsmOperand::InOut inout (inout_value.reg, inout_value.late, + std::unique_ptr<Expr> ( + ASTLoweringExpr::translate ( + *inout_value.expr.get ()))); + return inout; +} +HIR::InlineAsmOperand +translate_operand_split_in_out (const AST::InlineAsmOperand &operand) +{ + auto split_in_out_value = operand.get_split_in_out (); + struct HIR::InlineAsmOperand::SplitInOut split_in_out ( + split_in_out_value.reg, split_in_out_value.late, + std::unique_ptr<Expr> ( + ASTLoweringExpr::translate (*split_in_out_value.in_expr.get ())), + std::unique_ptr<Expr> ( + ASTLoweringExpr::translate (*split_in_out_value.out_expr.get ()))); + return split_in_out; +} +HIR::InlineAsmOperand +translate_operand_const (const AST::InlineAsmOperand &operand) +{ + auto const_value = operand.get_const (); + struct HIR::AnonConst anon_const (const_value.anon_const.id, + std::unique_ptr<Expr> ( + ASTLoweringExpr::translate ( + *const_value.anon_const.expr.get ()))); + struct HIR::InlineAsmOperand::Const cnst + { + anon_const + }; + return cnst; +} + +HIR::InlineAsmOperand +translate_operand_sym (const AST::InlineAsmOperand &operand) +{ + auto sym_value = operand.get_sym (); + struct HIR::InlineAsmOperand::Sym sym (std::unique_ptr<Expr> ( + ASTLoweringExpr::translate (*sym_value.expr.get ()))); + return sym; +} +HIR::InlineAsmOperand +translate_operand_label (const AST::InlineAsmOperand &operand) +{ + auto label_value = operand.get_label (); + struct HIR::InlineAsmOperand::Label label (label_value.label_name, + std::unique_ptr<Expr> ( + ASTLoweringExpr::translate ( + *label_value.expr.get ()))); + return label; +} +HIR::InlineAsmOperand +from_operand (const AST::InlineAsmOperand &operand) +{ + using RegisterType = AST::InlineAsmOperand::RegisterType; + auto type = operand.get_register_type (); + + /*In,*/ + /*Out,*/ + /*InOut,*/ + /*SplitInOut,*/ + /*Const,*/ + /*Sym,*/ + /*Label,*/ + switch (type) + { + case RegisterType::In: + return translate_operand_in (operand); + case RegisterType::Out: + return translate_operand_out (operand); + case RegisterType::InOut: + return translate_operand_inout (operand); + case RegisterType::SplitInOut: + return translate_operand_split_in_out (operand); + case RegisterType::Const: + return translate_operand_const (operand); + case RegisterType::Sym: + return translate_operand_sym (operand); + case RegisterType::Label: + return translate_operand_label (operand); + default: + rust_unreachable (); + } +} void ASTLoweringExpr::visit (AST::InlineAsm &expr) { @@ -837,12 +937,68 @@ ASTLoweringExpr::visit (AST::InlineAsm &expr) mappings.get_next_hir_id (crate_num), mappings.get_next_localdef_id (crate_num)); + std::vector<HIR::InlineAsmOperand> hir_operands; + const std::vector<AST::InlineAsmOperand> &ast_operands = expr.get_operands (); + /*int ast_operands_size = ast_operands.size ();*/ + for (auto &operand : ast_operands) + { + hir_operands.push_back (from_operand (operand)); + } + /*int hir_operands_size = hir_operands.size ();*/ + + /*rust_debug ("{bdbt} : There are %d ast operands prelowering and %d hir "*/ + /* "operands after lowering\n",*/ + /* ast_operands_size, hir_operands_size);*/ translated = new HIR::InlineAsm (expr.get_locus (), expr.is_global_asm, expr.get_template_ (), expr.get_template_strs (), - expr.get_operands (), expr.get_clobber_abi (), + hir_operands, expr.get_clobber_abi (), expr.get_options (), mapping); } + +void +ASTLoweringExpr::visit (AST::LlvmInlineAsm &expr) +{ + auto crate_num = mappings.get_current_crate (); + Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), + mappings.get_next_hir_id (crate_num), + mappings.get_next_localdef_id (crate_num)); + + std::vector<LlvmOperand> inputs; + std::vector<LlvmOperand> outputs; + + for (auto i : expr.get_inputs ()) + { + std::unique_ptr<Expr> inner_expr + = std::unique_ptr<Expr> (translate (*i.expr.get ())); + inputs.emplace_back (i.constraint, std::move (inner_expr)); + } + + for (auto o : expr.get_outputs ()) + { + std::unique_ptr<Expr> inner_expr + = std::unique_ptr<Expr> (translate (*o.expr.get ())); + outputs.emplace_back (o.constraint, std::move (inner_expr)); + } + + HIR::LlvmInlineAsm::Options options{expr.is_volatile (), + expr.is_stack_aligned (), + expr.get_dialect ()}; + + // We're not really supporting llvm_asm, only the bare minimum + // we're quite conservative here as the current code support more usecase. + rust_assert (outputs.size () == 0); + rust_assert (inputs.size () <= 1); + rust_assert (expr.get_clobbers ().size () <= 1); + rust_assert (expr.get_templates ().size () == 1); + rust_assert (expr.get_templates ()[0].symbol == ""); + + translated + = new HIR::LlvmInlineAsm (expr.get_locus (), inputs, outputs, + expr.get_templates (), expr.get_clobbers (), + options, expr.get_outer_attrs (), mapping); +} + void ASTLoweringExpr::visit (AST::FormatArgs &fmt) { diff --git a/gcc/rust/hir/rust-ast-lower-expr.h b/gcc/rust/hir/rust-ast-lower-expr.h index fc53786..adedeb3 100644 --- a/gcc/rust/hir/rust-ast-lower-expr.h +++ b/gcc/rust/hir/rust-ast-lower-expr.h @@ -113,7 +113,6 @@ public: void visit (AST::ContinueExpr &expr) override; void visit (AST::BorrowExpr &expr) override; void visit (AST::DereferenceExpr &expr) override; - void visit (AST::ErrorPropagationExpr &expr) override; void visit (AST::MatchExpr &expr) override; void visit (AST::RangeFromToExpr &expr) override; void visit (AST::RangeFromExpr &expr) override; @@ -123,6 +122,7 @@ public: void visit (AST::ClosureExprInner &expr) override; void visit (AST::ClosureExprInnerTyped &expr) override; void visit (AST::InlineAsm &expr) override; + void visit (AST::LlvmInlineAsm &expr) override; // Extra visitor for FormatArgs nodes void visit (AST::FormatArgs &fmt) override; diff --git a/gcc/rust/hir/rust-ast-lower-implitem.cc b/gcc/rust/hir/rust-ast-lower-implitem.cc index 5380d25..d815a71 100644 --- a/gcc/rust/hir/rust-ast-lower-implitem.cc +++ b/gcc/rust/hir/rust-ast-lower-implitem.cc @@ -22,6 +22,7 @@ #include "rust-ast-lower-expr.h" #include "rust-ast-lower-pattern.h" #include "rust-ast-lower-block.h" +#include "rust-hir-item.h" #include "rust-item.h" namespace Rust { @@ -131,7 +132,7 @@ ASTLowerImplItem::visit (AST::Function &function) Identifier function_name = function.get_function_name (); location_t locus = function.get_locus (); - HIR::SelfParam self_param = HIR::SelfParam::error (); + tl::optional<HIR::SelfParam> self_param = tl::nullopt; if (function.has_self_param ()) self_param = lower_self (function.get_self_param ()); @@ -140,6 +141,9 @@ ASTLowerImplItem::visit (AST::Function &function) ASTLoweringType::translate (function.get_return_type ())) : nullptr; + Defaultness defaultness + = function.is_default () ? Defaultness::Default : Defaultness::Final; + std::vector<HIR::FunctionParam> function_params; for (auto &p : function.get_function_params ()) { @@ -183,15 +187,15 @@ ASTLowerImplItem::visit (AST::Function &function) std::move (function_params), std::move (return_type), std::move (where_clause), std::move (function_body), std::move (vis), function.get_outer_attrs (), - std::move (self_param), locus); + std::move (self_param), defaultness, locus); - if (!fn->get_self_param ().is_error ()) + if (fn->is_method ()) { // insert mappings for self - mappings.insert_hir_self_param (&fn->get_self_param ()); + mappings.insert_hir_self_param (&fn->get_self_param_unchecked ()); mappings.insert_location ( - fn->get_self_param ().get_mappings ().get_hirid (), - fn->get_self_param ().get_locus ()); + fn->get_self_param_unchecked ().get_mappings ().get_hirid (), + fn->get_self_param_unchecked ().get_locus ()); } // add the mappings for the function params at the end @@ -245,9 +249,9 @@ ASTLowerTraitItem::visit (AST::Function &func) // set self parameter to error if this is a method // else lower to hir - HIR::SelfParam self_param = func.has_self_param () - ? lower_self (func.get_self_param ()) - : HIR::SelfParam::error (); + tl::optional<HIR::SelfParam> self_param = tl::nullopt; + if (func.has_self_param ()) + self_param = lower_self (func.get_self_param ()); std::vector<HIR::FunctionParam> function_params; for (auto &p : func.get_function_params ()) @@ -299,9 +303,10 @@ ASTLowerTraitItem::visit (AST::Function &func) if (func.has_self_param ()) { // insert mappings for self - mappings.insert_hir_self_param (&self_param); - mappings.insert_location (self_param.get_mappings ().get_hirid (), - self_param.get_locus ()); + // TODO: Is this correct ? Looks fishy + mappings.insert_hir_self_param (&*self_param); + mappings.insert_location (self_param->get_mappings ().get_hirid (), + self_param->get_locus ()); } // add the mappings for the function params at the end diff --git a/gcc/rust/hir/rust-ast-lower-item.cc b/gcc/rust/hir/rust-ast-lower-item.cc index 25345ce..f4396b5 100644 --- a/gcc/rust/hir/rust-ast-lower-item.cc +++ b/gcc/rust/hir/rust-ast-lower-item.cc @@ -451,13 +451,16 @@ ASTLoweringItem::visit (AST::Function &function) mappings.insert_location (function_body->get_mappings ().get_hirid (), function.get_locus ()); + Defaultness defaultness + = function.is_default () ? Defaultness::Default : Defaultness::Final; + auto fn = new HIR::Function (mapping, std::move (function_name), std::move (qualifiers), std::move (generic_params), std::move (function_params), std::move (return_type), std::move (where_clause), std::move (function_body), std::move (vis), function.get_outer_attrs (), - HIR::SelfParam::error (), locus); + tl::nullopt, defaultness, locus); // add the mappings for the function params at the end for (auto ¶m : fn->get_function_params ()) @@ -542,7 +545,7 @@ ASTLoweringItem::visit (AST::InherentImpl &impl_block) mapping, std::move (impl_items), std::move (generic_params), std::unique_ptr<HIR::Type> (impl_type), nullptr, where_clause, polarity, vis, impl_block.get_inner_attrs (), impl_block.get_outer_attrs (), - impl_block.get_locus ()); + impl_block.get_locus (), false); translated = hir_impl_block; mappings.insert_hir_impl_block (hir_impl_block); @@ -572,6 +575,12 @@ ASTLoweringItem::visit (AST::Trait &trait) generic_params = lower_generic_params (trait.get_generic_params ()); } + // TODO: separate "Self" from normal generic parameters + // in HIR as well as in AST? + HIR::GenericParam *self_param + = ASTLowerGenericParam::translate (trait.get_implicit_self ()); + generic_params.emplace (generic_params.begin (), self_param); + std::vector<std::unique_ptr<HIR::TypeParamBound>> type_param_bounds; if (trait.has_type_param_bounds ()) { @@ -600,17 +609,18 @@ ASTLoweringItem::visit (AST::Trait &trait) mappings.get_next_hir_id (crate_num), mappings.get_next_localdef_id (crate_num)); - auto trait_unsafety = Unsafety::Normal; - if (trait.is_unsafe ()) - { - trait_unsafety = Unsafety::Unsafe; - } + auto trait_unsafety + = trait.is_unsafe () ? Unsafety::Unsafe : Unsafety::Normal; HIR::Trait *hir_trait = new HIR::Trait (mapping, trait.get_identifier (), trait_unsafety, std::move (generic_params), std::move (type_param_bounds), where_clause, std::move (trait_items), vis, trait.get_outer_attrs (), trait.get_locus ()); + + if (trait.is_auto ()) + mappings.insert_auto_trait (hir_trait); + translated = hir_trait; for (auto trait_item_id : trait_item_ids) @@ -623,6 +633,7 @@ void ASTLoweringItem::visit (AST::TraitImpl &impl_block) { std::vector<std::unique_ptr<HIR::WhereClauseItem>> where_clause_items; + bool unsafe = impl_block.is_unsafe (); for (auto &item : impl_block.get_where_clause ().get_items ()) { HIR::WhereClauseItem *i = ASTLowerWhereClauseItem::translate (*item); @@ -689,14 +700,14 @@ ASTLoweringItem::visit (AST::TraitImpl &impl_block) } BoundPolarity polarity = impl_block.is_exclam () - ? BoundPolarity::RegularBound - : BoundPolarity::NegativeBound; + ? BoundPolarity::NegativeBound + : BoundPolarity::RegularBound; HIR::ImplBlock *hir_impl_block = new HIR::ImplBlock ( mapping, std::move (impl_items), std::move (generic_params), std::unique_ptr<HIR::Type> (impl_type), std::unique_ptr<HIR::TypePath> (trait_ref), where_clause, polarity, vis, impl_block.get_inner_attrs (), impl_block.get_outer_attrs (), - impl_block.get_locus ()); + impl_block.get_locus (), unsafe); translated = hir_impl_block; mappings.insert_hir_impl_block (hir_impl_block); diff --git a/gcc/rust/hir/rust-ast-lower-stmt.cc b/gcc/rust/hir/rust-ast-lower-stmt.cc index c359459..dbb1723 100644 --- a/gcc/rust/hir/rust-ast-lower-stmt.cc +++ b/gcc/rust/hir/rust-ast-lower-stmt.cc @@ -16,6 +16,7 @@ // along with GCC; see the file COPYING3. If not see // <http://www.gnu.org/licenses/>. +#include "optional.h" #include "rust-ast-lower-item.h" #include "rust-ast-lower-stmt.h" #include "rust-ast-lower-type.h" @@ -68,12 +69,23 @@ ASTLoweringStmt::visit (AST::LetStmt &stmt) { HIR::Pattern *variables = ASTLoweringPattern::translate (stmt.get_pattern (), true); - HIR::Type *type = stmt.has_type () - ? ASTLoweringType::translate (stmt.get_type ()) - : nullptr; - HIR::Expr *init_expression - = stmt.has_init_expr () ? ASTLoweringExpr::translate (stmt.get_init_expr ()) - : nullptr; + + tl::optional<std::unique_ptr<Type>> type = tl::nullopt; + + if (stmt.has_type ()) + type + = std::unique_ptr<Type> (ASTLoweringType::translate (stmt.get_type ())); + + tl::optional<std::unique_ptr<HIR::Expr>> init_expr = tl::nullopt; + tl::optional<std::unique_ptr<HIR::Expr>> else_expr = tl::nullopt; + + if (stmt.has_init_expr ()) + init_expr = std::unique_ptr<HIR::Expr> ( + ASTLoweringExpr::translate (stmt.get_init_expr ())); + + if (stmt.has_else_expr ()) + else_expr = std::unique_ptr<HIR::Expr> ( + ASTLoweringExpr::translate (stmt.get_else_expr ())); auto crate_num = mappings.get_current_crate (); Analysis::NodeMapping mapping (crate_num, stmt.get_node_id (), @@ -81,9 +93,9 @@ ASTLoweringStmt::visit (AST::LetStmt &stmt) UNKNOWN_LOCAL_DEFID); translated = new HIR::LetStmt (mapping, std::unique_ptr<HIR::Pattern> (variables), - std::unique_ptr<HIR::Expr> (init_expression), - std::unique_ptr<HIR::Type> (type), - stmt.get_outer_attrs (), stmt.get_locus ()); + std::move (init_expr), std::move (else_expr), + std::move (type), stmt.get_outer_attrs (), + stmt.get_locus ()); } void @@ -157,5 +169,11 @@ ASTLoweringStmt::visit (AST::TraitImpl &impl_block) translated = ASTLoweringItem::translate (impl_block); } +void +ASTLoweringStmt::visit (AST::StaticItem &var) +{ + translated = ASTLoweringItem::translate (var); +} + } // namespace HIR } // namespace Rust diff --git a/gcc/rust/hir/rust-ast-lower-stmt.h b/gcc/rust/hir/rust-ast-lower-stmt.h index 5b1e1b9..737a5f8 100644 --- a/gcc/rust/hir/rust-ast-lower-stmt.h +++ b/gcc/rust/hir/rust-ast-lower-stmt.h @@ -45,6 +45,7 @@ public: void visit (AST::Trait &trait) override; void visit (AST::InherentImpl &impl_block) override; void visit (AST::TraitImpl &impl_block) override; + void visit (AST::StaticItem &var) override; private: ASTLoweringStmt () : translated (nullptr), terminated (false) {} diff --git a/gcc/rust/hir/rust-ast-lower-type.cc b/gcc/rust/hir/rust-ast-lower-type.cc index f7cb863..a678f18 100644 --- a/gcc/rust/hir/rust-ast-lower-type.cc +++ b/gcc/rust/hir/rust-ast-lower-type.cc @@ -17,6 +17,11 @@ // <http://www.gnu.org/licenses/>. #include "rust-ast-lower-type.h" +#include "rust-hir-map.h" +#include "rust-hir-path.h" +#include "rust-hir-type.h" +#include "rust-path.h" +#include "rust-pattern.h" namespace Rust { namespace HIR { @@ -69,11 +74,20 @@ ASTLowerTypePath::visit (AST::TypePathSegment &segment) Analysis::NodeMapping mapping (crate_num, segment.get_node_id (), hirid, UNKNOWN_LOCAL_DEFID); - HIR::PathIdentSegment ident (segment.get_ident_segment ().as_string ()); - translated_segment - = new HIR::TypePathSegment (std::move (mapping), ident, - segment.get_separating_scope_resolution (), - segment.get_locus ()); + if (segment.is_lang_item ()) + { + translated_segment = new HIR::TypePathSegment (std::move (mapping), + segment.get_lang_item (), + segment.get_locus ()); + } + else + { + HIR::PathIdentSegment ident (segment.get_ident_segment ().as_string ()); + translated_segment + = new HIR::TypePathSegment (std::move (mapping), ident, + segment.get_separating_scope_resolution (), + segment.get_locus ()); + } } void @@ -81,10 +95,6 @@ ASTLowerTypePath::visit (AST::TypePathSegmentGeneric &segment) { std::vector<HIR::GenericArgsBinding> binding_args; // TODO - std::string segment_name = segment.get_ident_segment ().as_string (); - bool has_separating_scope_resolution - = segment.get_separating_scope_resolution (); - auto generic_args = lower_generic_args (segment.get_generic_args ()); auto crate_num = mappings.get_current_crate (); @@ -92,10 +102,24 @@ ASTLowerTypePath::visit (AST::TypePathSegmentGeneric &segment) Analysis::NodeMapping mapping (crate_num, segment.get_node_id (), hirid, UNKNOWN_LOCAL_DEFID); - translated_segment - = new HIR::TypePathSegmentGeneric (std::move (mapping), segment_name, - has_separating_scope_resolution, - generic_args, segment.get_locus ()); + if (segment.is_lang_item ()) + { + translated_segment + = new HIR::TypePathSegmentGeneric (std::move (mapping), + segment.get_lang_item (), + generic_args, segment.get_locus ()); + } + else + { + std::string segment_name = segment.get_ident_segment ().as_string (); + bool has_separating_scope_resolution + = segment.get_separating_scope_resolution (); + + translated_segment + = new HIR::TypePathSegmentGeneric (std::move (mapping), segment_name, + has_separating_scope_resolution, + generic_args, segment.get_locus ()); + } } void @@ -144,8 +168,15 @@ ASTLowerQualifiedPathInType::visit (AST::QualifiedPathInType &path) HIR::Type *qual_type = ASTLoweringType::translate (path.get_qualified_path_type ().get_type ()); - HIR::TypePath *qual_trait = ASTLowerTypePath::translate ( - path.get_qualified_path_type ().get_as_type_path ()); + + HIR::TypePath *qual_trait = nullptr; + if (!path.get_qualified_path_type ().is_error ()) + { + AST::QualifiedPathType &qualifier = path.get_qualified_path_type (); + if (qualifier.has_as_clause ()) + qual_trait + = ASTLowerTypePath::translate (qualifier.get_as_type_path ()); + } HIR::QualifiedPathType qual_path_type ( qual_mappings, std::unique_ptr<HIR::Type> (qual_type), @@ -428,6 +459,60 @@ ASTLoweringType::visit (AST::TraitObjectType &type) type.get_locus (), type.is_dyn ()); } +void +ASTLoweringType::visit (AST::ParenthesisedType &type) +{ + auto *inner = ASTLoweringType::translate (*type.get_type_in_parens (), + default_to_static_lifetime); + + auto crate_num = mappings.get_current_crate (); + Analysis::NodeMapping mapping (crate_num, type.get_node_id (), + mappings.get_next_hir_id (crate_num), + mappings.get_next_localdef_id (crate_num)); + + // FIXME: Do we actually need to know if a type is parenthesized in the HIR? + // or can we just use the type in parens? + translated + = new HIR::ParenthesisedType (mapping, std::unique_ptr<HIR::Type> (inner), + type.get_locus ()); +} + +void +ASTLoweringType::visit (AST::ImplTraitType &type) +{ + std::vector<std::unique_ptr<HIR::TypeParamBound>> bounds; + for (auto &bound : type.get_type_param_bounds ()) + { + auto b = ASTLoweringTypeBounds::translate (*bound.get ()); + bounds.push_back (std::unique_ptr<HIR::TypeParamBound> (b)); + } + + auto crate_num = mappings.get_current_crate (); + Analysis::NodeMapping mapping (crate_num, type.get_node_id (), + mappings.get_next_hir_id (crate_num), + mappings.get_next_localdef_id (crate_num)); + + translated + = new HIR::ImplTraitType (mapping, std::move (bounds), type.get_locus ()); +} + +void +ASTLoweringType::visit (AST::ImplTraitTypeOneBound &type) +{ + std::vector<std::unique_ptr<HIR::TypeParamBound>> bounds; + + auto b = ASTLoweringTypeBounds::translate (type.get_trait_bound ()); + bounds.push_back (std::unique_ptr<HIR::TypeParamBound> (b)); + + auto crate_num = mappings.get_current_crate (); + Analysis::NodeMapping mapping (crate_num, type.get_node_id (), + mappings.get_next_hir_id (crate_num), + mappings.get_next_localdef_id (crate_num)); + + translated + = new HIR::ImplTraitType (mapping, std::move (bounds), type.get_locus ()); +} + HIR::GenericParam * ASTLowerGenericParam::translate (AST::GenericParam ¶m) { @@ -446,16 +531,17 @@ void ASTLowerGenericParam::visit (AST::LifetimeParam ¶m) { auto crate_num = mappings.get_current_crate (); + AST::Lifetime lifetime = param.get_lifetime (); Analysis::NodeMapping mapping (crate_num, param.get_node_id (), mappings.get_next_hir_id (crate_num), mappings.get_next_localdef_id (crate_num)); - HIR::Lifetime lt (mapping, param.get_lifetime ().get_lifetime_type (), - param.get_lifetime ().get_lifetime_name (), - param.get_lifetime ().get_locus ()); + HIR::Lifetime lt (mapping, lifetime.get_lifetime_type (), + lifetime.get_lifetime_name (), lifetime.get_locus ()); translated = new HIR::LifetimeParam (mapping, lt, param.get_locus (), - std::vector<Lifetime> ()); + std::vector<Lifetime> (), + param.get_outer_attrs ()); } void @@ -471,7 +557,7 @@ ASTLowerGenericParam::visit (AST::ConstGenericParam ¶m) HIR::Expr *default_expr = nullptr; if (param.has_default_value ()) default_expr = ASTLoweringExpr::translate ( - param.get_default_value ().get_expression ()); + param.get_default_value_unchecked ().get_expression ()); translated = new HIR::ConstGenericParam (param.get_name ().as_string (), std::unique_ptr<Type> (type), @@ -482,7 +568,6 @@ ASTLowerGenericParam::visit (AST::ConstGenericParam ¶m) void ASTLowerGenericParam::visit (AST::TypeParam ¶m) { - AST::Attribute outer_attr = AST::Attribute::create_empty (); std::vector<std::unique_ptr<HIR::TypeParamBound>> type_param_bounds; if (param.has_type_param_bounds ()) { @@ -494,9 +579,11 @@ ASTLowerGenericParam::visit (AST::TypeParam ¶m) } } - HIR::Type *type = param.has_type () - ? ASTLoweringType::translate (param.get_type ()) - : nullptr; + tl::optional<std::unique_ptr<HIR::Type>> type = tl::nullopt; + if (param.has_type ()) + type + = tl::optional<std::unique_ptr<HIR::Type>> (std::unique_ptr<HIR::Type> ( + ASTLoweringType::translate (param.get_type ()))); auto crate_num = mappings.get_current_crate (); Analysis::NodeMapping mapping (crate_num, param.get_node_id (), @@ -506,7 +593,7 @@ ASTLowerGenericParam::visit (AST::TypeParam ¶m) translated = new HIR::TypeParam (mapping, param.get_type_representation (), param.get_locus (), std::move (type_param_bounds), - std::unique_ptr<Type> (type), std::move (outer_attr)); + std::move (type), param.get_outer_attrs ()); } HIR::TypeParamBound * diff --git a/gcc/rust/hir/rust-ast-lower-type.h b/gcc/rust/hir/rust-ast-lower-type.h index 5bb9a7e..4efaeee 100644 --- a/gcc/rust/hir/rust-ast-lower-type.h +++ b/gcc/rust/hir/rust-ast-lower-type.h @@ -21,6 +21,8 @@ #include "rust-ast-lower-base.h" #include "rust-ast-lower-expr.h" +#include "rust-hir-path.h" +#include "rust-type.h" namespace Rust { namespace HIR { @@ -78,6 +80,10 @@ public: void visit (AST::NeverType &type) override; void visit (AST::TraitObjectTypeOneBound &type) override; void visit (AST::TraitObjectType &type) override; + void visit (AST::ParenthesisedType &type) override; + + void visit (AST::ImplTraitType &type) override; + void visit (AST::ImplTraitTypeOneBound &type) override; private: ASTLoweringType (bool default_to_static_lifetime) diff --git a/gcc/rust/hir/rust-ast-lower.cc b/gcc/rust/hir/rust-ast-lower.cc index 5a5c93f..76bd135 100644 --- a/gcc/rust/hir/rust-ast-lower.cc +++ b/gcc/rust/hir/rust-ast-lower.cc @@ -24,6 +24,8 @@ #include "rust-ast-lower-type.h" #include "rust-ast-lower-pattern.h" #include "rust-ast-lower-struct-field-expr.h" +#include "rust-expr.h" +#include "rust-hir-expr.h" namespace Rust { namespace HIR { @@ -95,14 +97,22 @@ ASTLowering::go () void ASTLoweringBlock::visit (AST::BlockExpr &expr) { - auto label = lower_loop_label (expr.get_label ()); + tl::optional<HIR::LoopLabel> label; + if (expr.has_label ()) + label = lower_loop_label (expr.get_label ()); + else + label = tl::nullopt; std::vector<std::unique_ptr<HIR::Stmt>> block_stmts; bool block_did_terminate = false; for (auto &s : expr.get_statements ()) { - if (s->get_ast_kind () == AST::Kind::MACRO_INVOCATION) + // FIXME: We basically need to do that check for *every* single node in + // the AST. this isn't realistic and this should be turned into an + // optional, debug-visitor instead, which goes through the entire AST and + // checks if any of the nodes are macro invocations + if (s->get_stmt_kind () == AST::Stmt::Kind::MacroInvocation) rust_fatal_error ( s->get_locus (), "macro invocations should not get lowered to HIR - At " @@ -198,62 +208,144 @@ ASTLoweringIfBlock::visit (AST::IfExprConseqElse &expr) std::unique_ptr<HIR::ExprWithBlock> (else_block), expr.get_locus ()); } +/** + * Lowers the common part "if let 'pattern' = 'expr' { 'if_block' }" of + * IfLetExpr[ConseqElse]: + * - 'expr' is lowered into *BRANCH_VALUE + * - 'pattern' + 'if_block' are lowered and resulting ARM pushed in MATCH_ARMS + * - 'KASE_ELSE_EXPR' is the lowered HIR to be used in the else part. + * + * Looks like: + * + * match (expr) { + * pattern => {if_block} + * _ => kase_else_expr + * } + * + */ void -ASTLoweringIfLetBlock::visit (AST::IfLetExpr &expr) +ASTLoweringIfLetBlock::desugar_iflet (AST::IfLetExpr &expr, + HIR::Expr **branch_value, + HIR::Expr *kase_else_expr, + std::vector<HIR::MatchCase> &match_arms) { - std::vector<std::unique_ptr<HIR::Pattern>> patterns; + HIR::Expr *kase_expr; + std::vector<std::unique_ptr<HIR::Pattern>> match_arm_patterns; + + *branch_value = ASTLoweringExpr::translate (expr.get_value_expr ()); + kase_expr = ASTLoweringExpr::translate (expr.get_if_block ()); + + // (stable) if let only accepts a single pattern, but (unstable) if let chains + // need more than one pattern. + // We don't support if let chains, so only support a single pattern. + rust_assert (expr.get_patterns ().size () == 1); + for (auto &pattern : expr.get_patterns ()) { HIR::Pattern *ptrn = ASTLoweringPattern::translate (*pattern); - patterns.push_back (std::unique_ptr<HIR::Pattern> (ptrn)); + match_arm_patterns.push_back (std::unique_ptr<HIR::Pattern> (ptrn)); } - HIR::Expr *value_ptr = ASTLoweringExpr::translate (expr.get_value_expr ()); - bool ignored_terminated = false; - HIR::BlockExpr *block - = ASTLoweringBlock::translate (expr.get_if_block (), &ignored_terminated); + // The match arm corresponding to the if let pattern when it matches. + HIR::MatchArm arm (std::move (match_arm_patterns), expr.get_locus (), nullptr, + {}); auto crate_num = mappings.get_current_crate (); Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), mappings.get_next_hir_id (crate_num), UNKNOWN_LOCAL_DEFID); - translated = new HIR::IfLetExpr (mapping, std::move (patterns), - std::unique_ptr<HIR::Expr> (value_ptr), - std::unique_ptr<HIR::BlockExpr> (block), - expr.get_locus ()); + HIR::MatchCase kase (std::move (mapping), std::move (arm), + std::unique_ptr<HIR::Expr> (kase_expr)); + match_arms.push_back (std::move (kase)); + + // The default match arm when the if let pattern does not match + std::vector<std::unique_ptr<HIR::Pattern>> match_arm_patterns_wildcard; + Analysis::NodeMapping mapping_default (crate_num, expr.get_node_id (), + mappings.get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + std::unique_ptr<HIR::WildcardPattern> wc + = std::unique_ptr<HIR::WildcardPattern> ( + new HIR::WildcardPattern (mapping_default, expr.get_locus ())); + + match_arm_patterns_wildcard.push_back (std::move (wc)); + + HIR::MatchArm arm_default (std::move (match_arm_patterns_wildcard), + expr.get_locus (), nullptr, {}); + + HIR::MatchCase kase_else (std::move (mapping_default), + std::move (arm_default), + std::unique_ptr<HIR::Expr> (kase_else_expr)); + match_arms.push_back (std::move (kase_else)); } void -ASTLoweringIfLetBlock::visit (AST::IfLetExprConseqElse &expr) +ASTLoweringIfLetBlock::visit (AST::IfLetExpr &expr) { - std::vector<std::unique_ptr<HIR::Pattern>> patterns; - for (auto &pattern : expr.get_patterns ()) - { - HIR::Pattern *ptrn = ASTLoweringPattern::translate (*pattern); - patterns.push_back (std::unique_ptr<HIR::Pattern> (ptrn)); - } - HIR::Expr *value_ptr = ASTLoweringExpr::translate (expr.get_value_expr ()); + // Desugar: + // if let Some(y) = some_value { + // bar(); + // } + // + // into: + // + // match some_value { + // Some(y) => {bar();}, + // _ => () + // } + + HIR::Expr *branch_value; - bool ignored_terminated = false; - HIR::BlockExpr *block - = ASTLoweringBlock::translate (expr.get_if_block (), &ignored_terminated); + std::vector<HIR::MatchCase> match_arms; + auto crate_num = mappings.get_current_crate (); + Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), + mappings.get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); - HIR::ExprWithBlock *else_block - = ASTLoweringExprWithBlock::translate (expr.get_else_block (), - &ignored_terminated); + HIR::TupleExpr *unit + = new HIR::TupleExpr (mapping, {}, {}, {}, expr.get_locus ()); - rust_assert (else_block); + desugar_iflet (expr, &branch_value, unit, match_arms); + + translated + = new HIR::MatchExpr (mapping, std::unique_ptr<HIR::Expr> (branch_value), + std::move (match_arms), {}, {}, expr.get_locus ()); +} + +void +ASTLoweringIfLetBlock::visit (AST::IfLetExprConseqElse &expr) +{ + // desugar: + // if let Some(y) = some_value { + // bar(); + // } else { + // baz(); + // } + // + // into + // match some_value { + // Some(y) => {bar();}, + // _ => {baz();} + // } + // + + HIR::Expr *branch_value; + std::vector<HIR::MatchCase> match_arms; + + HIR::Expr *kase_else_expr + = ASTLoweringExpr::translate (expr.get_else_block ()); + + desugar_iflet (expr, &branch_value, kase_else_expr, match_arms); auto crate_num = mappings.get_current_crate (); Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), mappings.get_next_hir_id (crate_num), UNKNOWN_LOCAL_DEFID); - translated = new HIR::IfLetExprConseqElse ( - mapping, std::move (patterns), std::unique_ptr<HIR::Expr> (value_ptr), - std::unique_ptr<HIR::BlockExpr> (block), - std::unique_ptr<HIR::ExprWithBlock> (else_block), expr.get_locus ()); + translated + = new HIR::MatchExpr (mapping, std::unique_ptr<HIR::Expr> (branch_value), + std::move (match_arms), {}, {}, expr.get_locus ()); } // rust-ast-lower-struct-field-expr.h @@ -310,7 +402,10 @@ ASTLoweringExprWithBlock::visit (AST::WhileLoopExpr &expr) HIR::BlockExpr *loop_block = ASTLoweringBlock::translate (expr.get_loop_block (), &terminated); - HIR::LoopLabel loop_label = lower_loop_label (expr.get_loop_label ()); + tl::optional<HIR::LoopLabel> loop_label; + if (expr.has_loop_label ()) + loop_label = lower_loop_label (expr.get_loop_label ()); + HIR::Expr *loop_condition = ASTLoweringExpr::translate (expr.get_predicate_expr (), &terminated); @@ -330,24 +425,7 @@ ASTLoweringExprWithBlock::visit (AST::WhileLoopExpr &expr) void ASTLoweringExprWithBlock::visit (AST::ForLoopExpr &expr) { - // TODO FIXME - - // HIR::BlockExpr *loop_block - // = ASTLoweringBlock::translate (expr.get_loop_block ().get (), - // &terminated); - // HIR::LoopLabel loop_label = lower_loop_label (expr.get_loop_label ()); - // HIR::Expr *iterator_expr - // = ASTLoweringExpr::translate (expr.get_iterator_expr ().get (), - // &terminated); - // HIR::Pattern *loop_pattern - // = ASTLoweringPattern::translate (expr.get_pattern ().get ()); - - // auto crate_num = mappings->get_current_crate (); - // Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), - // mappings->get_next_hir_id (crate_num), - // UNKNOWN_LOCAL_DEFID); - - gcc_unreachable (); + rust_unreachable (); } void @@ -406,6 +484,18 @@ ASTLoweringExprWithBlock::visit (AST::MatchExpr &expr) void ASTLowerPathInExpression::visit (AST::PathInExpression &expr) { + auto crate_num = mappings.get_current_crate (); + Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), + mappings.get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + if (expr.is_lang_item ()) + { + translated = new HIR::PathInExpression (mapping, expr.get_lang_item (), + expr.get_locus (), false); + return; + } + std::vector<HIR::PathExprSegment> path_segments; auto &segments = expr.get_segments (); for (auto &s : segments) @@ -416,10 +506,6 @@ ASTLowerPathInExpression::visit (AST::PathInExpression &expr) HIR::PathExprSegment *lowered_seg = &path_segments.back (); mappings.insert_hir_path_expr_seg (lowered_seg); } - auto crate_num = mappings.get_current_crate (); - Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), - mappings.get_next_hir_id (crate_num), - UNKNOWN_LOCAL_DEFID); translated = new HIR::PathInExpression (mapping, std::move (path_segments), expr.get_locus (), diff --git a/gcc/rust/hir/rust-ast-lower.h b/gcc/rust/hir/rust-ast-lower.h index 079ffa9..cc74082 100644 --- a/gcc/rust/hir/rust-ast-lower.h +++ b/gcc/rust/hir/rust-ast-lower.h @@ -39,6 +39,11 @@ struct_field_name_exists (std::vector<HIR::StructField> &fields, Visibility translate_visibility (const AST::Visibility &vis); +/** + * Main base class used for lowering AST to HIR. + * + * Every subclass should provide a translate() method that takes an AST node and + * lowers it to some HIR stored in the TRANSLATED member. */ class ASTLowering { public: diff --git a/gcc/rust/hir/rust-hir-dump.cc b/gcc/rust/hir/rust-hir-dump.cc index 4ae9cba..cb32f68 100644 --- a/gcc/rust/hir/rust-hir-dump.cc +++ b/gcc/rust/hir/rust-hir-dump.cc @@ -22,9 +22,9 @@ #include "rust-hir-path.h" #include "rust-hir-type.h" #include "rust-hir.h" -#include <string> #include "rust-attribute-values.h" #include "tree/rust-hir-expr.h" +#include "rust-system.h" namespace Rust { namespace HIR { @@ -315,6 +315,14 @@ Dump::do_functionparam (FunctionParam &e) void Dump::do_pathpattern (PathPattern &e) { + if (e.get_path_kind () == PathPattern::Kind::LangItem) + { + put_field ("segments", "#[lang = \"" + + LangItem::ToString (e.get_lang_item ()) + + "\"]"); + return; + } + std::string str = ""; for (const auto &segment : e.get_segments ()) @@ -359,7 +367,8 @@ Dump::do_matcharm (MatchArm &e) // FIXME Can't remember how to handle that. Let's see later. // do_outer_attrs(e); visit_collection ("match_arm_patterns", e.get_patterns ()); - visit_field ("guard_expr", e.get_guard_expr ()); + if (e.has_match_arm_guard ()) + visit_field ("guard_expr", e.get_guard_expr ()); end ("MatchArm"); } @@ -387,7 +396,10 @@ void Dump::do_typepathsegment (TypePathSegment &e) { do_mappings (e.get_mappings ()); - put_field ("ident_segment", e.get_ident_segment ().as_string ()); + if (e.is_lang_item ()) + put_field ("ident_segment", LangItem::PrettyString (e.get_lang_item ())); + else + put_field ("ident_segment", e.get_ident_segment ().as_string ()); } void @@ -401,9 +413,13 @@ void Dump::do_qualifiedpathtype (QualifiedPathType &e) { do_mappings (e.get_mappings ()); - visit_field ("type", e.get_type ()); + if (e.has_type ()) + visit_field ("type", e.get_type ()); + else + put_field ("type", "none"); - visit_field ("trait", e.get_trait ()); + if (e.has_trait ()) + visit_field ("trait", e.get_trait ()); } void @@ -464,17 +480,6 @@ Dump::do_baseloopexpr (BaseLoopExpr &e) } void -Dump::do_ifletexpr (IfLetExpr &e) -{ - do_expr (e); - - visit_collection ("match_arm_patterns", e.get_patterns ()); - - visit_field ("value", e.get_scrutinee_expr ()); - visit_field ("if_block", e.get_if_block ()); -} - -void Dump::do_struct (Struct &e) { do_vis_item (e); @@ -531,14 +536,18 @@ Dump::do_traitfunctiondecl (TraitFunctionDecl &e) else put_field ("function_params", "empty"); - visit_field ("return_type", e.get_return_type ()); + if (e.has_return_type ()) + visit_field ("return_type", e.get_return_type ()); + else + put_field ("return_type", "none"); if (e.has_where_clause ()) put_field ("where_clause", e.get_where_clause ().as_string ()); else put_field ("where_clause", "none"); - put_field ("self", e.get_self ().as_string ()); + if (e.is_method ()) + put_field ("self", e.get_self_unchecked ().as_string ()); end ("TraitFunctionDecl"); } @@ -811,7 +820,7 @@ Dump::visit (QualifiedPathInType &e) end_field ("path_type"); begin_field ("associated_segment"); - do_typepathsegment (*e.get_associated_segment ()); + do_typepathsegment (e.get_associated_segment ()); end_field ("associated_segment"); visit_collection ("segments", e.get_segments ()); @@ -922,7 +931,7 @@ Dump::visit (ArithmeticOrLogicalExpr &e) } put_field ("expr_type", str); do_operatorexpr (e); - visit_field ("right_expr", *e.get_rhs ()); + visit_field ("right_expr", e.get_rhs ()); end ("ArithmeticOrLogicalExpr"); } @@ -957,7 +966,7 @@ Dump::visit (ComparisonExpr &e) } put_field ("expr_type", str); do_operatorexpr (e); - visit_field ("right_expr", *e.get_rhs ()); + visit_field ("right_expr", e.get_rhs ()); end ("ComparisonExpr"); } @@ -980,7 +989,7 @@ Dump::visit (LazyBooleanExpr &e) } do_operatorexpr (e); - visit_field ("right_expr", *e.get_rhs ()); + visit_field ("right_expr", e.get_rhs ()); end ("LazyBooleanExpr"); } @@ -998,7 +1007,7 @@ Dump::visit (AssignmentExpr &e) { begin ("AssignmentExpr"); do_operatorexpr (e); - visit_field ("right_expr", *e.get_rhs ()); + visit_field ("right_expr", e.get_rhs ()); end ("AssignmentExpr"); } @@ -1008,7 +1017,7 @@ Dump::visit (CompoundAssignmentExpr &e) begin ("CompoundAssignmentExpr"); do_operatorexpr (e); - visit_field ("right_expr", *e.get_rhs ()); + visit_field ("right_expr", e.get_rhs ()); std::string str; @@ -1182,7 +1191,7 @@ Dump::visit (StructExprStructFields &e) if (!e.has_struct_base ()) put_field ("struct_base", "none"); else - put_field ("struct_base", e.get_struct_base ()->as_string ()); + put_field ("struct_base", e.get_struct_base ().as_string ()); end ("StructExprStructFields"); } @@ -1193,7 +1202,7 @@ Dump::visit (StructExprStructBase &e) begin ("StructExprStructBase"); do_structexprstruct (e); - put_field ("struct_base", e.get_struct_base ()->as_string ()); + put_field ("struct_base", e.get_struct_base ().as_string ()); end ("StructExprStructBase"); } @@ -1252,13 +1261,17 @@ Dump::visit (ClosureExpr &e) auto oa = param.get_outer_attrs (); do_outer_attrs (oa); visit_field ("pattern", param.get_pattern ()); - visit_field ("type", param.get_type ()); + + if (param.has_type_given ()) + visit_field ("type", param.get_type ()); + end ("ClosureParam"); } end_field ("params"); } - visit_field ("return_type", e.get_return_type ()); + if (e.has_return_type ()) + visit_field ("return_type", e.get_return_type ()); visit_field ("expr", e.get_expr ()); end ("ClosureExpr"); @@ -1270,10 +1283,15 @@ Dump::visit (BlockExpr &e) begin ("BlockExpr"); do_expr (e); do_inner_attrs (e); + put_field ("tail_reachable", std::to_string (e.is_tail_reachable ())); + + if (e.has_label ()) + put_field ("label", e.get_label ().as_string ()); visit_collection ("statements", e.get_statements ()); - visit_field ("expr", e.get_final_expr ()); + if (e.has_final_expr ()) + visit_field ("expr", e.get_final_expr ()); end ("BlockExpr"); } @@ -1302,7 +1320,10 @@ Dump::visit (BreakExpr &e) else put_field ("label", "none"); - visit_field ("break_expr ", e.get_expr ()); + if (e.has_break_expr ()) + visit_field ("break_expr ", e.get_expr ()); + else + put_field ("break_expr", "none"); end ("BreakExpr"); } @@ -1372,7 +1393,8 @@ Dump::visit (ReturnExpr &e) begin ("ReturnExpr"); do_mappings (e.get_mappings ()); - visit_field ("return_expr", e.get_expr ()); + if (e.has_return_expr ()) + visit_field ("return_expr", e.get_expr ()); end ("ReturnExpr"); } @@ -1440,23 +1462,6 @@ Dump::visit (IfExprConseqElse &e) } void -Dump::visit (IfLetExpr &e) -{ - begin ("IfLetExpr"); - do_ifletexpr (e); - end ("IfLetExpr"); -} - -void -Dump::visit (IfLetExprConseqElse &e) -{ - begin ("IfLetExprConseqElse"); - do_ifletexpr (e); - visit_field ("else_block", e.get_else_block ()); - end ("IfLetExprConseqElse"); -} - -void Dump::visit (MatchExpr &e) { begin ("MatchExpr"); @@ -1505,16 +1510,22 @@ Dump::visit (InlineAsm &e) {} void +Dump::visit (LlvmInlineAsm &e) +{} + +void Dump::visit (TypeParam &e) { begin ("TypeParam"); - put_field ("outer_attr", e.get_outer_attribute ().as_string ()); + auto &outer_attrs = e.get_outer_attrs (); + do_outer_attrs (outer_attrs); put_field ("type_representation", e.get_type_representation ().as_string ()); visit_collection ("type_param_bounds", e.get_type_param_bounds ()); - visit_field ("type", e.get_type ()); + if (e.has_type ()) + visit_field ("type", e.get_type ()); end ("TypeParam"); } @@ -1680,7 +1691,8 @@ Dump::visit (Function &e) put_field ("function_params", "empty"); } - visit_field ("return_type", e.get_return_type ()); + if (e.has_function_return_type ()) + visit_field ("return_type", e.get_return_type ()); if (!e.has_where_clause ()) put_field ("where_clause", "none"); @@ -1688,7 +1700,8 @@ Dump::visit (Function &e) put_field ("where clause", e.get_where_clause ().as_string ()); visit_field ("function_body", e.get_definition ()); - put_field ("self", e.get_self_param ().as_string ()); + if (e.is_method ()) + put_field ("self", e.get_self_param_unchecked ().as_string ()); end ("Function"); } @@ -1709,7 +1722,7 @@ Dump::visit (TypeAlias &e) else put_field ("where clause", e.get_where_clause ().as_string ()); - put_field ("type", e.get_type_aliased ()->as_string ()); + put_field ("type", e.get_type_aliased ().as_string ()); end ("TypeAlias"); } @@ -1913,7 +1926,8 @@ Dump::visit (TraitItemFunc &e) do_traitfunctiondecl (e.get_decl ()); - visit_field ("block_expr", e.get_block_expr ()); + if (e.has_definition ()) + visit_field ("block_expr", e.get_block_expr ()); end ("TraitItemFunc"); } @@ -1926,7 +1940,9 @@ Dump::visit (TraitItemConst &e) put_field ("name", e.get_name ().as_string ()); visit_field ("type", e.get_type ()); - visit_field ("expr", e.get_expr ()); + if (e.has_expr ()) + visit_field ("expr", e.get_expr ()); + end ("TraitItemConst"); } @@ -2028,7 +2044,8 @@ Dump::visit (ExternalFunctionItem &e) put_field ("has_variadics", std::to_string (e.is_variadic ())); - visit_field ("return_type", e.get_return_type ()); + if (e.has_return_type ()) + visit_field ("return_type", e.get_return_type ()); end ("ExternalFunctionItem"); } @@ -2075,7 +2092,7 @@ Dump::visit (IdentifierPattern &e) put_field ("mut", std::to_string (e.is_mut ())); if (e.has_pattern_to_bind ()) - put_field ("to_bind", e.get_to_bind ()->as_string ()); + put_field ("to_bind", e.get_to_bind ().as_string ()); else put_field ("to_bind", "none"); @@ -2119,8 +2136,8 @@ Dump::visit (RangePattern &e) { begin ("RangePattern"); do_mappings (e.get_mappings ()); - put_field ("lower", e.get_lower_bound ()->as_string ()); - put_field ("upper", e.get_upper_bound ()->as_string ()); + put_field ("lower", e.get_lower_bound ().as_string ()); + put_field ("upper", e.get_upper_bound ().as_string ()); put_field ("has_ellipsis_syntax", std::to_string (e.get_has_ellipsis_syntax ())); end ("RangePattern"); @@ -2132,7 +2149,7 @@ Dump::visit (ReferencePattern &e) begin ("ReferencePattern"); do_mappings (e.get_mappings ()); put_field ("mut", std::to_string (e.is_mut ())); - put_field ("pattern", e.get_referenced_pattern ()->as_string ()); + put_field ("pattern", e.get_referenced_pattern ().as_string ()); end ("ReferencePattern"); } @@ -2144,7 +2161,7 @@ Dump::visit (StructPatternFieldTuplePat &e) auto oa = e.get_outer_attrs (); do_outer_attrs (oa); put_field ("index", std::to_string (e.get_index ())); - put_field ("tuple_pattern", e.get_tuple_pattern ()->as_string ()); + put_field ("tuple_pattern", e.get_tuple_pattern ().as_string ()); end ("StructPatternFieldTuplePat"); } @@ -2155,7 +2172,7 @@ Dump::visit (StructPatternFieldIdentPat &e) auto oa = e.get_outer_attrs (); do_outer_attrs (oa); put_field ("ident", e.get_identifier ().as_string ()); - put_field ("ident_pattern", e.get_pattern ()->as_string ()); + put_field ("ident_pattern", e.get_pattern ().as_string ()); end ("StructPatternFieldIdentPat"); } @@ -2273,10 +2290,12 @@ Dump::visit (LetStmt &e) auto oa = e.get_outer_attrs (); do_outer_attrs (oa); - put_field ("variable_pattern", e.get_pattern ()->as_string ()); + put_field ("variable_pattern", e.get_pattern ().as_string ()); - visit_field ("type", e.get_type ()); - visit_field ("init_expr", e.get_init_expr ()); + if (e.has_type ()) + visit_field ("type", e.get_type ()); + if (e.has_init_expr ()) + visit_field ("init_expr", e.get_init_expr ()); end ("LetStmt"); } @@ -2334,20 +2353,11 @@ Dump::visit (ParenthesisedType &e) { begin ("ParenthesisedType"); do_type (e); - put_field ("type_in_parens", e.get_type_in_parens ()->as_string ()); + put_field ("type_in_parens", e.get_type_in_parens ().as_string ()); end ("ParenthesisedType"); } void -Dump::visit (ImplTraitTypeOneBound &e) -{ - begin ("ImplTraitTypeOneBound"); - do_type (e); - visit_field ("trait_bound", e.get_trait_bound ()); - end ("ImplTraitTypeOneBound"); -} - -void Dump::visit (TupleType &e) { begin ("TupleType"); @@ -2370,7 +2380,7 @@ Dump::visit (RawPointerType &e) begin ("RawPointerType"); do_type (e); put_field ("mut", Rust::enum_to_str (e.get_mut ())); - put_field ("type", e.get_type ()->as_string ()); + put_field ("type", e.get_type ().as_string ()); end ("RawPointerType"); } @@ -2381,7 +2391,7 @@ Dump::visit (ReferenceType &e) do_type (e); put_field ("lifetime", e.get_lifetime ().as_string ()); put_field ("mut", enum_to_str (e.get_mut ())); - put_field ("type", e.get_base_type ()->as_string ()); + put_field ("type", e.get_base_type ().as_string ()); end ("ReferenceType"); } @@ -2438,7 +2448,9 @@ Dump::visit (BareFunctionType &e) end_field ("params"); } - visit_field ("return_type", e.get_return_type ()); + if (e.has_return_type ()) + visit_field ("return_type", e.get_return_type ()); + put_field ("is_variadic", std::to_string (e.get_is_variadic ())); end ("BareFunctionType"); } diff --git a/gcc/rust/hir/rust-hir-dump.h b/gcc/rust/hir/rust-hir-dump.h index b3a2020..45b1708 100644 --- a/gcc/rust/hir/rust-hir-dump.h +++ b/gcc/rust/hir/rust-hir-dump.h @@ -80,7 +80,6 @@ private: void do_type (Type &); void do_expr (Expr &); void do_ifexpr (IfExpr &); - void do_ifletexpr (IfLetExpr &); void do_pathexpr (PathExpr &); void do_pathpattern (PathPattern &); void do_genericargs (GenericArgs &); @@ -162,13 +161,12 @@ private: virtual void visit (WhileLetLoopExpr &) override; virtual void visit (IfExpr &) override; virtual void visit (IfExprConseqElse &) override; - virtual void visit (IfLetExpr &) override; - virtual void visit (IfLetExprConseqElse &) override; virtual void visit (MatchExpr &) override; virtual void visit (AwaitExpr &) override; virtual void visit (AsyncBlockExpr &) override; virtual void visit (InlineAsm &) override; + virtual void visit (LlvmInlineAsm &) override; virtual void visit (TypeParam &) override; virtual void visit (ConstGenericParam &) override; @@ -240,7 +238,6 @@ private: virtual void visit (ImplTraitType &) override; virtual void visit (TraitObjectType &) override; virtual void visit (ParenthesisedType &) override; - virtual void visit (ImplTraitTypeOneBound &) override; virtual void visit (TupleType &) override; virtual void visit (NeverType &) override; virtual void visit (RawPointerType &) override; diff --git a/gcc/rust/hir/tree/rust-hir-attrs.h b/gcc/rust/hir/tree/rust-hir-attrs.h new file mode 100644 index 0000000..3e2b1d8 --- /dev/null +++ b/gcc/rust/hir/tree/rust-hir-attrs.h @@ -0,0 +1,56 @@ + +// Copyright (C) 2020-2024 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_HIR_ATTRS_H +#define RUST_HIR_ATTRS_H + +#include "rust-ast.h" + +namespace Rust { +namespace HIR { + +class WithOuterAttrs +{ +protected: + AST::AttrVec outer_attrs; + +public: + AST::AttrVec &get_outer_attrs () { return outer_attrs; } + const AST::AttrVec &get_outer_attrs () const { return outer_attrs; } + + WithOuterAttrs (AST::AttrVec outer_attrs) + : outer_attrs (std::move (outer_attrs)){}; +}; + +class WithInnerAttrs +{ +protected: + AST::AttrVec inner_attrs; + +public: + AST::AttrVec get_inner_attrs () const { return inner_attrs; } + + WithInnerAttrs (AST::AttrVec inner_attrs) + : inner_attrs (std::move (inner_attrs)){}; +}; + +} // namespace HIR +} // namespace Rust + +#endif diff --git a/gcc/rust/hir/tree/rust-hir-bound-abstract.h b/gcc/rust/hir/tree/rust-hir-bound-abstract.h new file mode 100644 index 0000000..ffc915b --- /dev/null +++ b/gcc/rust/hir/tree/rust-hir-bound-abstract.h @@ -0,0 +1,65 @@ +// Copyright (C) 2020-2024 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_HIR_BOUND_ABSTRACT_H +#define RUST_HIR_BOUND_ABSTRACT_H + +#include "rust-hir-visitable.h" +#include "rust-system.h" +#include "rust-hir-map.h" + +namespace Rust { +namespace HIR { + +/* Abstract base class representing a type param bound - Lifetime and TraitBound + * extends it */ +class TypeParamBound : public FullVisitable +{ +public: + using FullVisitable::accept_vis; + enum BoundType + { + LIFETIME, + TRAITBOUND + }; + + virtual ~TypeParamBound () {} + + // Unique pointer custom clone function + std::unique_ptr<TypeParamBound> clone_type_param_bound () const + { + return std::unique_ptr<TypeParamBound> (clone_type_param_bound_impl ()); + } + + virtual std::string as_string () const = 0; + + virtual Analysis::NodeMapping get_mappings () const = 0; + + virtual location_t get_locus () const = 0; + + virtual BoundType get_bound_type () const = 0; + +protected: + // Clone function implementation as pure virtual method + virtual TypeParamBound *clone_type_param_bound_impl () const = 0; +}; + +} // namespace HIR +} // namespace Rust + +#endif diff --git a/gcc/rust/hir/tree/rust-hir-bound.h b/gcc/rust/hir/tree/rust-hir-bound.h new file mode 100644 index 0000000..8fa6a22 --- /dev/null +++ b/gcc/rust/hir/tree/rust-hir-bound.h @@ -0,0 +1,82 @@ +// Copyright (C) 2020-2024 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_HIR_BOUND_H +#define RUST_HIR_BOUND_H + +#include "rust-hir-bound-abstract.h" +#include "rust-common.h" +#include "rust-hir-path.h" + +namespace Rust { +namespace HIR { + +// Represents a lifetime (and is also a kind of type param bound) +class Lifetime : public TypeParamBound +{ +private: + AST::Lifetime::LifetimeType lifetime_type; + std::string lifetime_name; + location_t locus; + Analysis::NodeMapping mappings; + +public: + // Constructor + Lifetime (Analysis::NodeMapping mapping, AST::Lifetime::LifetimeType type, + std::string name, location_t locus) + : lifetime_type (type), lifetime_name (std::move (name)), locus (locus), + mappings (mapping) + {} + + // Returns true if the lifetime is in an error state. + std::string as_string () const override; + + void accept_vis (HIRFullVisitor &vis) override; + + WARN_UNUSED_RESULT const std::string &get_name () const + { + return lifetime_name; + } + + AST::Lifetime::LifetimeType get_lifetime_type () const + { + return lifetime_type; + } + + location_t get_locus () const override final { return locus; } + + Analysis::NodeMapping get_mappings () const override final + { + return mappings; + } + + BoundType get_bound_type () const final override { return LIFETIME; } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + Lifetime *clone_type_param_bound_impl () const override + { + return new Lifetime (*this); + } +}; + +} // namespace HIR +} // namespace Rust + +#endif diff --git a/gcc/rust/hir/tree/rust-hir-expr-abstract.h b/gcc/rust/hir/tree/rust-hir-expr-abstract.h new file mode 100644 index 0000000..5bc5d89 --- /dev/null +++ b/gcc/rust/hir/tree/rust-hir-expr-abstract.h @@ -0,0 +1,175 @@ +// Copyright (C) 2020-2024 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_HIR_EXPR_ABSTRACT_H +#define RUST_HIR_EXPR_ABSTRACT_H + +#include "rust-ast.h" +#include "rust-hir-visitable.h" +#include "rust-hir-node.h" + +namespace Rust { +namespace HIR { + +// Base expression HIR node - abstract +class Expr : public Node, virtual public FullVisitable +{ +public: + using FullVisitable::accept_vis; + +protected: + AST::AttrVec outer_attrs; + Analysis::NodeMapping mappings; + +public: + enum BlockType + { + WITH_BLOCK, + WITHOUT_BLOCK, + }; + + enum ExprType + { + Lit, + Operator, + Grouped, + Array, + ArrayIndex, + Tuple, + TupleIdx, + Struct, + Call, + MethodCall, + FieldAccess, + Closure, + Block, + Continue, + Break, + Range, + Return, + UnsafeBlock, + BaseLoop, + If, + IfLet, + Match, + Await, + AsyncBlock, + Path, + InlineAsm, + LlvmInlineAsm, + }; + + BaseKind get_hir_kind () override final { return Node::BaseKind::EXPR; } + + const AST::AttrVec &get_outer_attrs () const { return outer_attrs; } + + // Unique pointer custom clone function + std::unique_ptr<Expr> clone_expr () const + { + return std::unique_ptr<Expr> (clone_expr_impl ()); + } + + // TODO: make pure virtual if move out outer attributes to derived classes + virtual std::string as_string () const; + + virtual ~Expr () {} + + virtual location_t get_locus () const = 0; + + const Analysis::NodeMapping &get_mappings () const { return mappings; } + + // Clone function implementation as pure virtual method + virtual Expr *clone_expr_impl () const = 0; + + virtual BlockType get_block_expr_type () const = 0; + + virtual ExprType get_expression_type () const = 0; + + virtual void accept_vis (HIRExpressionVisitor &vis) = 0; + +protected: + // Constructor + Expr (Analysis::NodeMapping mappings, + AST::AttrVec outer_attribs = AST::AttrVec ()); + + // TODO: think of less hacky way to implement this kind of thing + // Sets outer attributes. + void set_outer_attrs (AST::AttrVec outer_attrs_to_set) + { + outer_attrs = std::move (outer_attrs_to_set); + } +}; + +// HIR node for an expression without an accompanying block - abstract +class ExprWithoutBlock : public Expr +{ +protected: + // Constructor + ExprWithoutBlock (Analysis::NodeMapping mappings, + AST::AttrVec outer_attribs = AST::AttrVec ()); + + // pure virtual clone implementation + virtual ExprWithoutBlock *clone_expr_without_block_impl () const = 0; + + /* Save having to specify two clone methods in derived classes by making expr + * clone return exprwithoutblock clone. Hopefully won't affect performance too + * much. */ + ExprWithoutBlock *clone_expr_impl () const override + { + return clone_expr_without_block_impl (); + } + +public: + // Unique pointer custom clone function + std::unique_ptr<ExprWithoutBlock> clone_expr_without_block () const + { + return std::unique_ptr<ExprWithoutBlock> (clone_expr_without_block_impl ()); + } + + BlockType get_block_expr_type () const final override + { + return BlockType::WITHOUT_BLOCK; + }; +}; + +// Base path expression HIR node - abstract +class PathExpr : public ExprWithoutBlock +{ +protected: + PathExpr (Analysis::NodeMapping mappings, AST::AttrVec outer_attribs) + : ExprWithoutBlock (std::move (mappings), std::move (outer_attribs)) + {} + +public: + /* Replaces the outer attributes of this path expression with the given outer + * attributes. */ + void replace_outer_attrs (AST::AttrVec outer_attrs) + { + set_outer_attrs (std::move (outer_attrs)); + } + + ExprType get_expression_type () const final override + { + return ExprType::Path; + } +}; + +} // namespace HIR +} // namespace Rust + +#endif diff --git a/gcc/rust/hir/tree/rust-hir-expr.cc b/gcc/rust/hir/tree/rust-hir-expr.cc new file mode 100644 index 0000000..266c79c --- /dev/null +++ b/gcc/rust/hir/tree/rust-hir-expr.cc @@ -0,0 +1,1490 @@ +// Copyright (C) 2020-2024 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-hir-expr.h" +#include "rust-operators.h" +#include "rust-hir-stmt.h" + +namespace Rust { +namespace HIR { + +Expr::Expr (Analysis::NodeMapping mappings, AST::AttrVec outer_attribs) + : outer_attrs (std::move (outer_attribs)), mappings (std::move (mappings)) +{} + +ExprWithoutBlock::ExprWithoutBlock (Analysis::NodeMapping mappings, + AST::AttrVec outer_attribs) + : Expr (std::move (mappings), std::move (outer_attribs)) +{} + +LoopLabel::LoopLabel (Analysis::NodeMapping mapping, Lifetime loop_label, + location_t locus) + : label (std::move (loop_label)), locus (locus), mappings (mapping) +{} + +ExprWithBlock::ExprWithBlock (Analysis::NodeMapping mappings, + AST::AttrVec outer_attrs) + : Expr (std::move (mappings), std::move (outer_attrs)) +{} + +LiteralExpr::LiteralExpr (Analysis::NodeMapping mappings, + std::string value_as_string, Literal::LitType type, + PrimitiveCoreType type_hint, location_t locus, + AST::AttrVec outer_attrs) + : ExprWithoutBlock (std::move (mappings), std::move (outer_attrs)), + literal (std::move (value_as_string), type, type_hint), locus (locus) +{} + +LiteralExpr::LiteralExpr (Analysis::NodeMapping mappings, Literal literal, + location_t locus, AST::AttrVec outer_attrs) + : ExprWithoutBlock (std::move (mappings), std::move (outer_attrs)), + literal (std::move (literal)), locus (locus) +{} + +OperatorExpr::OperatorExpr (Analysis::NodeMapping mappings, + std::unique_ptr<Expr> main_or_left_expr, + AST::AttrVec outer_attribs, location_t locus) + : ExprWithoutBlock (std::move (mappings), std::move (outer_attribs)), + locus (locus), main_or_left_expr (std::move (main_or_left_expr)) +{} + +OperatorExpr::OperatorExpr (OperatorExpr const &other) + : ExprWithoutBlock (other), locus (other.locus), + main_or_left_expr (other.main_or_left_expr->clone_expr ()) +{} + +OperatorExpr & +OperatorExpr::operator= (OperatorExpr const &other) +{ + ExprWithoutBlock::operator= (other); + main_or_left_expr = other.main_or_left_expr->clone_expr (); + locus = other.locus; + // outer_attrs = other.outer_attrs; + + return *this; +} + +BorrowExpr::BorrowExpr (Analysis::NodeMapping mappings, + std::unique_ptr<Expr> borrow_lvalue, Mutability mut, + bool raw, AST::AttrVec outer_attribs, location_t locus) + : OperatorExpr (std::move (mappings), std::move (borrow_lvalue), + std::move (outer_attribs), locus), + mut (mut), raw (raw) +{} + +DereferenceExpr::DereferenceExpr (Analysis::NodeMapping mappings, + std::unique_ptr<Expr> deref_lvalue, + AST::AttrVec outer_attribs, location_t locus) + : OperatorExpr (std::move (mappings), std::move (deref_lvalue), + std::move (outer_attribs), locus) +{} + +ErrorPropagationExpr::ErrorPropagationExpr ( + Analysis::NodeMapping mappings, std::unique_ptr<Expr> potential_error_value, + AST::AttrVec outer_attribs, location_t locus) + : OperatorExpr (std::move (mappings), std::move (potential_error_value), + std::move (outer_attribs), locus) +{} + +NegationExpr::NegationExpr (Analysis::NodeMapping mappings, + std::unique_ptr<Expr> negated_value, + ExprType expr_kind, AST::AttrVec outer_attribs, + location_t locus) + : OperatorExpr (std::move (mappings), std::move (negated_value), + std::move (outer_attribs), locus), + expr_type (expr_kind) +{} + +ArithmeticOrLogicalExpr::ArithmeticOrLogicalExpr ( + Analysis::NodeMapping mappings, std::unique_ptr<Expr> left_value, + std::unique_ptr<Expr> right_value, ExprType expr_kind, location_t locus) + : OperatorExpr (std::move (mappings), std::move (left_value), AST::AttrVec (), + locus), + expr_type (expr_kind), right_expr (std::move (right_value)) +{} + +ArithmeticOrLogicalExpr::ArithmeticOrLogicalExpr ( + ArithmeticOrLogicalExpr const &other) + : OperatorExpr (other), expr_type (other.expr_type), + right_expr (other.right_expr->clone_expr ()) +{} + +ArithmeticOrLogicalExpr & +ArithmeticOrLogicalExpr::operator= (ArithmeticOrLogicalExpr const &other) +{ + OperatorExpr::operator= (other); + // main_or_left_expr = other.main_or_left_expr->clone_expr(); + right_expr = other.right_expr->clone_expr (); + expr_type = other.expr_type; + + return *this; +} + +ComparisonExpr::ComparisonExpr (Analysis::NodeMapping mappings, + std::unique_ptr<Expr> left_value, + std::unique_ptr<Expr> right_value, + ExprType comparison_kind, location_t locus) + : OperatorExpr (std::move (mappings), std::move (left_value), AST::AttrVec (), + locus), + expr_type (comparison_kind), right_expr (std::move (right_value)) +{} + +ComparisonExpr::ComparisonExpr (ComparisonExpr const &other) + : OperatorExpr (other), expr_type (other.expr_type), + right_expr (other.right_expr->clone_expr ()) +{} + +ComparisonExpr & +ComparisonExpr::operator= (ComparisonExpr const &other) +{ + OperatorExpr::operator= (other); + // main_or_left_expr = other.main_or_left_expr->clone_expr(); + right_expr = other.right_expr->clone_expr (); + expr_type = other.expr_type; + // outer_attrs = other.outer_attrs; + + return *this; +} + +LazyBooleanExpr::LazyBooleanExpr (Analysis::NodeMapping mappings, + std::unique_ptr<Expr> left_bool_expr, + std::unique_ptr<Expr> right_bool_expr, + ExprType expr_kind, location_t locus) + : OperatorExpr (std::move (mappings), std::move (left_bool_expr), + AST::AttrVec (), locus), + expr_type (expr_kind), right_expr (std::move (right_bool_expr)) +{} + +LazyBooleanExpr::LazyBooleanExpr (LazyBooleanExpr const &other) + : OperatorExpr (other), expr_type (other.expr_type), + right_expr (other.right_expr->clone_expr ()) +{} + +LazyBooleanExpr & +LazyBooleanExpr::operator= (LazyBooleanExpr const &other) +{ + OperatorExpr::operator= (other); + // main_or_left_expr = other.main_or_left_expr->clone_expr(); + right_expr = other.right_expr->clone_expr (); + expr_type = other.expr_type; + + return *this; +} + +TypeCastExpr::TypeCastExpr (Analysis::NodeMapping mappings, + std::unique_ptr<Expr> expr_to_cast, + std::unique_ptr<Type> type_to_cast_to, + location_t locus) + : OperatorExpr (std::move (mappings), std::move (expr_to_cast), + AST::AttrVec (), locus), + type_to_convert_to (std::move (type_to_cast_to)) +{} + +TypeCastExpr::TypeCastExpr (TypeCastExpr const &other) + : OperatorExpr (other), + type_to_convert_to (other.type_to_convert_to->clone_type ()) +{} + +TypeCastExpr & +TypeCastExpr::operator= (TypeCastExpr const &other) +{ + OperatorExpr::operator= (other); + // main_or_left_expr = other.main_or_left_expr->clone_expr(); + type_to_convert_to = other.type_to_convert_to->clone_type (); + + return *this; +} + +AssignmentExpr::AssignmentExpr (Analysis::NodeMapping mappings, + std::unique_ptr<Expr> value_to_assign_to, + std::unique_ptr<Expr> value_to_assign, + location_t locus) + : OperatorExpr (std::move (mappings), std::move (value_to_assign_to), + AST::AttrVec (), locus), + right_expr (std::move (value_to_assign)) +{} + +AssignmentExpr::AssignmentExpr (AssignmentExpr const &other) + : OperatorExpr (other), right_expr (other.right_expr->clone_expr ()) +{} + +AssignmentExpr & +AssignmentExpr::operator= (AssignmentExpr const &other) +{ + OperatorExpr::operator= (other); + // main_or_left_expr = other.main_or_left_expr->clone_expr(); + right_expr = other.right_expr->clone_expr (); + // outer_attrs = other.outer_attrs; + + return *this; +} + +CompoundAssignmentExpr::CompoundAssignmentExpr ( + Analysis::NodeMapping mappings, std::unique_ptr<Expr> value_to_assign_to, + std::unique_ptr<Expr> value_to_assign, ExprType expr_kind, location_t locus) + : OperatorExpr (std::move (mappings), std::move (value_to_assign_to), + AST::AttrVec (), locus), + expr_type (expr_kind), right_expr (std::move (value_to_assign)) +{} + +CompoundAssignmentExpr::CompoundAssignmentExpr ( + CompoundAssignmentExpr const &other) + : OperatorExpr (other), expr_type (other.expr_type), + right_expr (other.right_expr->clone_expr ()) +{} + +CompoundAssignmentExpr & +CompoundAssignmentExpr::operator= (CompoundAssignmentExpr const &other) +{ + OperatorExpr::operator= (other); + // main_or_left_expr = other.main_or_left_expr->clone_expr(); + right_expr = other.right_expr->clone_expr (); + expr_type = other.expr_type; + // outer_attrs = other.outer_attrs; + + return *this; +} + +GroupedExpr::GroupedExpr (Analysis::NodeMapping mappings, + std::unique_ptr<Expr> parenthesised_expr, + AST::AttrVec inner_attribs, + AST::AttrVec outer_attribs, location_t locus) + : ExprWithoutBlock (std::move (mappings), std::move (outer_attribs)), + WithInnerAttrs (std::move (inner_attribs)), + expr_in_parens (std::move (parenthesised_expr)), locus (locus) +{} + +GroupedExpr::GroupedExpr (GroupedExpr const &other) + : ExprWithoutBlock (other), WithInnerAttrs (other.inner_attrs), + expr_in_parens (other.expr_in_parens->clone_expr ()), locus (other.locus) +{} + +GroupedExpr & +GroupedExpr::operator= (GroupedExpr const &other) +{ + ExprWithoutBlock::operator= (other); + inner_attrs = other.inner_attrs; + expr_in_parens = other.expr_in_parens->clone_expr (); + locus = other.locus; + // outer_attrs = other.outer_attrs; + + return *this; +} + +ArrayElemsValues::ArrayElemsValues (Analysis::NodeMapping mappings, + std::vector<std::unique_ptr<Expr>> elems) + : ArrayElems (mappings), values (std::move (elems)) +{} + +ArrayElemsValues::ArrayElemsValues (ArrayElemsValues const &other) + : ArrayElems (other) +{ + values.reserve (other.values.size ()); + for (const auto &e : other.values) + values.push_back (e->clone_expr ()); +} + +ArrayElemsValues & +ArrayElemsValues::operator= (ArrayElemsValues const &other) +{ + values.reserve (other.values.size ()); + for (const auto &e : other.values) + values.push_back (e->clone_expr ()); + + return *this; +} + +ArrayElemsCopied::ArrayElemsCopied (Analysis::NodeMapping mappings, + std::unique_ptr<Expr> copied_elem, + std::unique_ptr<Expr> copy_amount) + : ArrayElems (mappings), elem_to_copy (std::move (copied_elem)), + num_copies (std::move (copy_amount)) +{} + +ArrayElemsCopied::ArrayElemsCopied (ArrayElemsCopied const &other) + : ArrayElems (other), elem_to_copy (other.elem_to_copy->clone_expr ()), + num_copies (other.num_copies->clone_expr ()) +{} + +ArrayElemsCopied & +ArrayElemsCopied::operator= (ArrayElemsCopied const &other) +{ + elem_to_copy = other.elem_to_copy->clone_expr (); + num_copies = other.num_copies->clone_expr (); + + return *this; +} + +ArrayExpr::ArrayExpr (Analysis::NodeMapping mappings, + std::unique_ptr<ArrayElems> array_elems, + AST::AttrVec inner_attribs, AST::AttrVec outer_attribs, + location_t locus) + : ExprWithoutBlock (std::move (mappings), std::move (outer_attribs)), + WithInnerAttrs (std::move (inner_attribs)), + internal_elements (std::move (array_elems)), locus (locus) +{} + +ArrayExpr::ArrayExpr (ArrayExpr const &other) + : ExprWithoutBlock (other), WithInnerAttrs (other.inner_attrs), + locus (other.locus) +{ + if (other.has_array_elems ()) + internal_elements = other.internal_elements->clone_array_elems (); +} + +ArrayExpr & +ArrayExpr::operator= (ArrayExpr const &other) +{ + ExprWithoutBlock::operator= (other); + inner_attrs = other.inner_attrs; + if (other.has_array_elems ()) + internal_elements = other.internal_elements->clone_array_elems (); + locus = other.locus; + // outer_attrs = other.outer_attrs; + + return *this; +} + +ArrayIndexExpr::ArrayIndexExpr (Analysis::NodeMapping mappings, + std::unique_ptr<Expr> array_expr, + std::unique_ptr<Expr> array_index_expr, + AST::AttrVec outer_attribs, location_t locus) + : ExprWithoutBlock (std::move (mappings), std::move (outer_attribs)), + array_expr (std::move (array_expr)), + index_expr (std::move (array_index_expr)), locus (locus) +{} + +ArrayIndexExpr::ArrayIndexExpr (ArrayIndexExpr const &other) + : ExprWithoutBlock (other), array_expr (other.array_expr->clone_expr ()), + index_expr (other.index_expr->clone_expr ()), locus (other.locus) +{} + +ArrayIndexExpr & +ArrayIndexExpr::operator= (ArrayIndexExpr const &other) +{ + ExprWithoutBlock::operator= (other); + array_expr = other.array_expr->clone_expr (); + index_expr = other.index_expr->clone_expr (); + // outer_attrs = other.outer_attrs; + locus = other.locus; + + return *this; +} + +TupleExpr::TupleExpr (Analysis::NodeMapping mappings, + std::vector<std::unique_ptr<Expr>> tuple_elements, + AST::AttrVec inner_attribs, AST::AttrVec outer_attribs, + location_t locus) + : ExprWithoutBlock (std::move (mappings), std::move (outer_attribs)), + WithInnerAttrs (std::move (inner_attribs)), + tuple_elems (std::move (tuple_elements)), locus (locus) +{} + +TupleExpr::TupleExpr (TupleExpr const &other) + : ExprWithoutBlock (other), WithInnerAttrs (other.inner_attrs), + locus (other.locus) +{ + tuple_elems.reserve (other.tuple_elems.size ()); + for (const auto &e : other.tuple_elems) + tuple_elems.push_back (e->clone_expr ()); +} + +TupleExpr & +TupleExpr::operator= (TupleExpr const &other) +{ + ExprWithoutBlock::operator= (other); + inner_attrs = other.inner_attrs; + locus = other.locus; + + tuple_elems.reserve (other.tuple_elems.size ()); + for (const auto &e : other.tuple_elems) + tuple_elems.push_back (e->clone_expr ()); + + return *this; +} + +TupleIndexExpr::TupleIndexExpr (Analysis::NodeMapping mappings, + std::unique_ptr<Expr> tuple_expr, + TupleIndex index, AST::AttrVec outer_attribs, + location_t locus) + : ExprWithoutBlock (std::move (mappings), std::move (outer_attribs)), + tuple_expr (std::move (tuple_expr)), tuple_index (index), locus (locus) +{} + +TupleIndexExpr::TupleIndexExpr (TupleIndexExpr const &other) + : ExprWithoutBlock (other), tuple_expr (other.tuple_expr->clone_expr ()), + tuple_index (other.tuple_index), locus (other.locus) +{} + +TupleIndexExpr & +TupleIndexExpr::operator= (TupleIndexExpr const &other) +{ + ExprWithoutBlock::operator= (other); + tuple_expr = other.tuple_expr->clone_expr (); + tuple_index = other.tuple_index; + locus = other.locus; + // outer_attrs = other.outer_attrs; + + return *this; +} + +StructExpr::StructExpr (Analysis::NodeMapping mappings, + PathInExpression struct_path, + AST::AttrVec outer_attribs) + : ExprWithoutBlock (std::move (mappings), std::move (outer_attribs)), + struct_name (std::move (struct_path)) +{} + +StructExprStruct::StructExprStruct (Analysis::NodeMapping mappings, + PathInExpression struct_path, + AST::AttrVec inner_attribs, + AST::AttrVec outer_attribs, + location_t locus) + : StructExpr (std::move (mappings), std::move (struct_path), + std::move (outer_attribs)), + WithInnerAttrs (std::move (inner_attribs)), locus (locus) +{} + +StructBase::StructBase (std::unique_ptr<Expr> base_struct_ptr) + : base_struct (std::move (base_struct_ptr)) +{} + +StructBase::StructBase (StructBase const &other) +{ + /* HACK: gets around base_struct pointer being null (e.g. if no struct base + * exists) */ + if (other.base_struct != nullptr) + other.base_struct->clone_expr (); +} + +StructBase & +StructBase::operator= (StructBase const &other) +{ + base_struct = other.base_struct->clone_expr (); + + return *this; +} + +StructExprField::StructExprField (Analysis::NodeMapping mapping, + location_t locus) + : mappings (mapping), locus (locus) +{} + +StructExprFieldIdentifier::StructExprFieldIdentifier ( + Analysis::NodeMapping mapping, Identifier field_identifier, location_t locus) + : StructExprField (mapping, locus), field_name (std::move (field_identifier)) +{} + +StructExprFieldWithVal::StructExprFieldWithVal ( + Analysis::NodeMapping mapping, std::unique_ptr<Expr> field_value, + location_t locus) + : StructExprField (mapping, locus), value (std::move (field_value)) +{} + +StructExprFieldWithVal::StructExprFieldWithVal ( + StructExprFieldWithVal const &other) + : StructExprField (other.mappings, other.locus), + value (other.value->clone_expr ()) +{} + +StructExprFieldWithVal & +StructExprFieldWithVal::operator= (StructExprFieldWithVal const &other) +{ + value = other.value->clone_expr (); + mappings = other.mappings; + locus = other.locus; + + return *this; +} + +StructExprFieldIdentifierValue::StructExprFieldIdentifierValue ( + Analysis::NodeMapping mapping, Identifier field_identifier, + std::unique_ptr<Expr> field_value, location_t locus) + : StructExprFieldWithVal (mapping, std::move (field_value), locus), + field_name (std::move (field_identifier)) +{} + +StructExprFieldIndexValue::StructExprFieldIndexValue ( + Analysis::NodeMapping mapping, TupleIndex tuple_index, + std::unique_ptr<Expr> field_value, location_t locus) + : StructExprFieldWithVal (mapping, std::move (field_value), locus), + index (tuple_index) +{} + +StructExprStructFields::StructExprStructFields ( + Analysis::NodeMapping mappings, PathInExpression struct_path, + std::vector<std::unique_ptr<StructExprField>> expr_fields, location_t locus, + tl::optional<std::unique_ptr<StructBase>> base_struct, + AST::AttrVec inner_attribs = AST::AttrVec (), + AST::AttrVec outer_attribs = AST::AttrVec ()) + : StructExprStruct (std::move (mappings), std::move (struct_path), + std::move (inner_attribs), std::move (outer_attribs), + locus), + fields (std::move (expr_fields)), struct_base (std::move (base_struct)) +{} + +StructExprStructFields::StructExprStructFields ( + StructExprStructFields const &other) + : StructExprStruct (other), + struct_base (other.has_struct_base () + ? tl::optional<std::unique_ptr<StructBase>> ( + std::make_unique<StructBase> (*other.struct_base.value ())) + : tl::nullopt), + union_index (other.union_index) +{ + fields.reserve (other.fields.size ()); + for (const auto &e : other.fields) + fields.push_back (e->clone_struct_expr_field ()); +} + +StructExprStructFields & +StructExprStructFields::operator= (StructExprStructFields const &other) +{ + StructExprStruct::operator= (other); + struct_base = other.has_struct_base () + ? tl::optional<std::unique_ptr<StructBase>> ( + std::make_unique<StructBase> (*other.struct_base.value ())) + : tl::nullopt; + union_index = other.union_index; + + fields.reserve (other.fields.size ()); + for (const auto &e : other.fields) + fields.push_back (e->clone_struct_expr_field ()); + + return *this; +} + +StructExprStructBase::StructExprStructBase (Analysis::NodeMapping mappings, + PathInExpression struct_path, + StructBase base_struct, + AST::AttrVec inner_attribs, + AST::AttrVec outer_attribs, + location_t locus) + : StructExprStruct (std::move (mappings), std::move (struct_path), + std::move (inner_attribs), std::move (outer_attribs), + locus), + struct_base (std::move (base_struct)) +{} + +CallExpr::CallExpr (Analysis::NodeMapping mappings, + std::unique_ptr<Expr> function_expr, + std::vector<std::unique_ptr<Expr>> function_params, + AST::AttrVec outer_attribs, location_t locus) + : ExprWithoutBlock (std::move (mappings), std::move (outer_attribs)), + function (std::move (function_expr)), params (std::move (function_params)), + locus (locus) +{} + +CallExpr::CallExpr (CallExpr const &other) + : ExprWithoutBlock (other), function (other.function->clone_expr ()), + locus (other.locus) +/*, params(other.params),*/ { + params.reserve (other.params.size ()); + for (const auto &e : other.params) + params.push_back (e->clone_expr ()); +} + +CallExpr & +CallExpr::operator= (CallExpr const &other) +{ + ExprWithoutBlock::operator= (other); + function = other.function->clone_expr (); + locus = other.locus; + // params = other.params; + // outer_attrs = other.outer_attrs; + + params.reserve (other.params.size ()); + for (const auto &e : other.params) + params.push_back (e->clone_expr ()); + + return *this; +} + +MethodCallExpr::MethodCallExpr ( + Analysis::NodeMapping mappings, std::unique_ptr<Expr> call_receiver, + PathExprSegment method_path, std::vector<std::unique_ptr<Expr>> method_params, + AST::AttrVec outer_attribs, location_t locus) + : ExprWithoutBlock (std::move (mappings), std::move (outer_attribs)), + receiver (std::move (call_receiver)), method_name (std::move (method_path)), + params (std::move (method_params)), locus (locus) +{} + +MethodCallExpr::MethodCallExpr (MethodCallExpr const &other) + : ExprWithoutBlock (other), receiver (other.receiver->clone_expr ()), + method_name (other.method_name), locus (other.locus) +/*, params(other.params),*/ { + params.reserve (other.params.size ()); + for (const auto &e : other.params) + params.push_back (e->clone_expr ()); +} + +MethodCallExpr & +MethodCallExpr::operator= (MethodCallExpr const &other) +{ + ExprWithoutBlock::operator= (other); + receiver = other.receiver->clone_expr (); + method_name = other.method_name; + locus = other.locus; + // params = other.params; + // outer_attrs = other.outer_attrs; + + params.reserve (other.params.size ()); + for (const auto &e : other.params) + params.push_back (e->clone_expr ()); + + return *this; +} + +FieldAccessExpr::FieldAccessExpr (Analysis::NodeMapping mappings, + std::unique_ptr<Expr> field_access_receiver, + Identifier field_name, + AST::AttrVec outer_attribs, location_t locus) + : ExprWithoutBlock (std::move (mappings), std::move (outer_attribs)), + receiver (std::move (field_access_receiver)), + field (std::move (field_name)), locus (locus) +{} + +FieldAccessExpr::FieldAccessExpr (FieldAccessExpr const &other) + : ExprWithoutBlock (other), receiver (other.receiver->clone_expr ()), + field (other.field), locus (other.locus) +{} + +FieldAccessExpr & +FieldAccessExpr::operator= (FieldAccessExpr const &other) +{ + ExprWithoutBlock::operator= (other); + receiver = other.receiver->clone_expr (); + field = other.field; + locus = other.locus; + // outer_attrs = other.outer_attrs; + + return *this; +} + +ClosureParam::ClosureParam (std::unique_ptr<Pattern> param_pattern, + location_t locus, std::unique_ptr<Type> param_type, + std::vector<AST::Attribute> outer_attrs) + : outer_attrs (std::move (outer_attrs)), pattern (std::move (param_pattern)), + type (std::move (param_type)), locus (locus) +{} + +ClosureParam::ClosureParam (ClosureParam const &other) + : pattern (other.pattern->clone_pattern ()) +{ + // guard to protect from null pointer dereference + if (other.pattern != nullptr) + pattern = other.pattern->clone_pattern (); + if (other.type != nullptr) + type = other.type->clone_type (); +} + +ClosureParam & +ClosureParam::operator= (ClosureParam const &other) +{ + outer_attrs = other.outer_attrs; + + // guard to protect from null pointer dereference + if (other.pattern != nullptr) + pattern = other.pattern->clone_pattern (); + else + pattern = nullptr; + if (other.type != nullptr) + type = other.type->clone_type (); + else + type = nullptr; + + return *this; +} + +ClosureExpr::ClosureExpr (Analysis::NodeMapping mappings, + std::vector<ClosureParam> closure_params, + std::unique_ptr<Type> closure_return_type, + std::unique_ptr<Expr> closure_expr, bool has_move, + AST::AttrVec outer_attribs, location_t locus) + : ExprWithoutBlock (std::move (mappings), std::move (outer_attribs)), + has_move (has_move), params (std::move (closure_params)), locus (locus), + return_type (std::move (closure_return_type)), + expr (std::move (closure_expr)) +{} + +ClosureExpr::ClosureExpr (ClosureExpr const &other) + : ExprWithoutBlock (other.get_mappings (), other.get_outer_attrs ()) +{ + return_type + = other.has_return_type () ? other.return_type->clone_type () : nullptr; + expr = other.expr->clone_expr (); + params = other.params; + has_move = other.has_move; +} + +ClosureExpr & +ClosureExpr::operator= (ClosureExpr const &other) +{ + mappings = other.mappings; + return_type + = other.has_return_type () ? other.return_type->clone_type () : nullptr; + expr = other.expr->clone_expr (); + params = other.params; + has_move = other.has_move; + + return *this; +} + +BlockExpr::BlockExpr (Analysis::NodeMapping mappings, + std::vector<std::unique_ptr<Stmt>> block_statements, + std::unique_ptr<Expr> block_expr, bool tail_reachable, + AST::AttrVec inner_attribs, AST::AttrVec outer_attribs, + tl::optional<LoopLabel> label, location_t start_locus, + location_t end_locus) + : ExprWithBlock (std::move (mappings), std::move (outer_attribs)), + WithInnerAttrs (std::move (inner_attribs)), + statements (std::move (block_statements)), expr (std::move (block_expr)), + tail_reachable (tail_reachable), label (std::move (label)), + start_locus (start_locus), end_locus (end_locus) +{} + +BlockExpr::BlockExpr (BlockExpr const &other) + : ExprWithBlock (other), /*statements(other.statements),*/ + WithInnerAttrs (other.inner_attrs), label (other.label), + start_locus (other.start_locus), end_locus (other.end_locus) +{ + // guard to protect from null pointer dereference + if (other.expr != nullptr) + expr = other.expr->clone_expr (); + + statements.reserve (other.statements.size ()); + for (const auto &e : other.statements) + statements.push_back (e->clone_stmt ()); +} + +BlockExpr & +BlockExpr::operator= (BlockExpr const &other) +{ + ExprWithBlock::operator= (other); + // statements = other.statements; + expr = other.expr->clone_expr (); + inner_attrs = other.inner_attrs; + start_locus = other.end_locus; + end_locus = other.end_locus; + // outer_attrs = other.outer_attrs; + + statements.reserve (other.statements.size ()); + for (const auto &e : other.statements) + statements.push_back (e->clone_stmt ()); + + return *this; +} + +ContinueExpr::ContinueExpr (Analysis::NodeMapping mappings, location_t locus, + tl::optional<Lifetime> label, + AST::AttrVec outer_attribs) + : ExprWithoutBlock (std::move (mappings), std::move (outer_attribs)), + label (std::move (label)), locus (locus) +{} + +BreakExpr::BreakExpr (Analysis::NodeMapping mappings, location_t locus, + tl::optional<Lifetime> break_label, + std::unique_ptr<Expr> expr_in_break, + AST::AttrVec outer_attribs) + : ExprWithoutBlock (std::move (mappings), std::move (outer_attribs)), + label (std::move (break_label)), break_expr (std::move (expr_in_break)), + locus (locus) +{} + +BreakExpr::BreakExpr (BreakExpr const &other) + : ExprWithoutBlock (other), label (other.label), locus (other.locus) +{ + // guard to protect from null pointer dereference + if (other.break_expr != nullptr) + break_expr = other.break_expr->clone_expr (); +} + +BreakExpr & +BreakExpr::operator= (BreakExpr const &other) +{ + ExprWithoutBlock::operator= (other); + label = other.label; + break_expr = other.break_expr->clone_expr (); + locus = other.locus; + // outer_attrs = other.outer_attrs; + + return *this; +} + +RangeExpr::RangeExpr (Analysis::NodeMapping mappings, location_t locus) + : ExprWithoutBlock (std::move (mappings), AST::AttrVec ()), locus (locus) +{} + +RangeFromToExpr::RangeFromToExpr (Analysis::NodeMapping mappings, + std::unique_ptr<Expr> range_from, + std::unique_ptr<Expr> range_to, + location_t locus) + : RangeExpr (std::move (mappings), locus), from (std::move (range_from)), + to (std::move (range_to)) +{} + +RangeFromToExpr::RangeFromToExpr (RangeFromToExpr const &other) + : RangeExpr (other), from (other.from->clone_expr ()), + to (other.to->clone_expr ()) +{} + +RangeFromToExpr & +RangeFromToExpr::operator= (RangeFromToExpr const &other) +{ + RangeExpr::operator= (other); + from = other.from->clone_expr (); + to = other.to->clone_expr (); + + return *this; +} + +RangeFromExpr::RangeFromExpr (Analysis::NodeMapping mappings, + std::unique_ptr<Expr> range_from, + location_t locus) + : RangeExpr (std::move (mappings), locus), from (std::move (range_from)) +{} + +RangeFromExpr::RangeFromExpr (RangeFromExpr const &other) + : RangeExpr (other), from (other.from->clone_expr ()) +{} + +RangeFromExpr & +RangeFromExpr::operator= (RangeFromExpr const &other) +{ + RangeExpr::operator= (other); + from = other.from->clone_expr (); + + return *this; +} + +RangeToExpr::RangeToExpr (Analysis::NodeMapping mappings, + std::unique_ptr<Expr> range_to, location_t locus) + : RangeExpr (std::move (mappings), locus), to (std::move (range_to)) +{} + +RangeToExpr::RangeToExpr (RangeToExpr const &other) + : RangeExpr (other), to (other.to->clone_expr ()) +{} + +RangeToExpr & +RangeToExpr::operator= (RangeToExpr const &other) +{ + RangeExpr::operator= (other); + to = other.to->clone_expr (); + + return *this; +} + +RangeFullExpr::RangeFullExpr (Analysis::NodeMapping mappings, location_t locus) + : RangeExpr (std::move (mappings), locus) +{} + +RangeFromToInclExpr::RangeFromToInclExpr (Analysis::NodeMapping mappings, + std::unique_ptr<Expr> range_from, + std::unique_ptr<Expr> range_to, + location_t locus) + : RangeExpr (std::move (mappings), locus), from (std::move (range_from)), + to (std::move (range_to)) +{} + +RangeFromToInclExpr::RangeFromToInclExpr (RangeFromToInclExpr const &other) + : RangeExpr (other), from (other.from->clone_expr ()), + to (other.to->clone_expr ()) +{} + +RangeFromToInclExpr & +RangeFromToInclExpr::operator= (RangeFromToInclExpr const &other) +{ + RangeExpr::operator= (other); + from = other.from->clone_expr (); + to = other.to->clone_expr (); + + return *this; +} + +RangeToInclExpr::RangeToInclExpr (Analysis::NodeMapping mappings, + std::unique_ptr<Expr> range_to, + location_t locus) + : RangeExpr (std::move (mappings), locus), to (std::move (range_to)) +{} + +RangeToInclExpr::RangeToInclExpr (RangeToInclExpr const &other) + : RangeExpr (other), to (other.to->clone_expr ()) +{} + +RangeToInclExpr & +RangeToInclExpr::operator= (RangeToInclExpr const &other) +{ + RangeExpr::operator= (other); + to = other.to->clone_expr (); + + return *this; +} + +ReturnExpr::ReturnExpr (Analysis::NodeMapping mappings, location_t locus, + std::unique_ptr<Expr> returned_expr, + AST::AttrVec outer_attribs) + : ExprWithoutBlock (std::move (mappings), std::move (outer_attribs)), + return_expr (std::move (returned_expr)), locus (locus) +{} + +ReturnExpr::ReturnExpr (ReturnExpr const &other) + : ExprWithoutBlock (other), locus (other.locus) +{ + // guard to protect from null pointer dereference + if (other.return_expr != nullptr) + return_expr = other.return_expr->clone_expr (); +} + +ReturnExpr & +ReturnExpr::operator= (ReturnExpr const &other) +{ + ExprWithoutBlock::operator= (other); + return_expr = other.return_expr->clone_expr (); + locus = other.locus; + // outer_attrs = other.outer_attrs; + + return *this; +} + +UnsafeBlockExpr::UnsafeBlockExpr (Analysis::NodeMapping mappings, + std::unique_ptr<BlockExpr> block_expr, + AST::AttrVec outer_attribs, location_t locus) + : ExprWithBlock (std::move (mappings), std::move (outer_attribs)), + expr (std::move (block_expr)), locus (locus) +{} + +UnsafeBlockExpr::UnsafeBlockExpr (UnsafeBlockExpr const &other) + : ExprWithBlock (other), expr (other.expr->clone_block_expr ()), + locus (other.locus) +{} + +UnsafeBlockExpr & +UnsafeBlockExpr::operator= (UnsafeBlockExpr const &other) +{ + ExprWithBlock::operator= (other); + expr = other.expr->clone_block_expr (); + locus = other.locus; + // outer_attrs = other.outer_attrs; + + return *this; +} + +BaseLoopExpr::BaseLoopExpr (Analysis::NodeMapping mappings, + std::unique_ptr<BlockExpr> loop_block, + location_t locus, + tl::optional<LoopLabel> loop_label, + AST::AttrVec outer_attribs) + : ExprWithBlock (std::move (mappings), std::move (outer_attribs)), + loop_label (std::move (loop_label)), loop_block (std::move (loop_block)), + locus (locus) +{} + +BaseLoopExpr::BaseLoopExpr (BaseLoopExpr const &other) + : ExprWithBlock (other), loop_label (other.loop_label), + loop_block (other.loop_block->clone_block_expr ()), locus (other.locus) +{} + +BaseLoopExpr & +BaseLoopExpr::operator= (BaseLoopExpr const &other) +{ + ExprWithBlock::operator= (other); + loop_block = other.loop_block->clone_block_expr (); + loop_label = other.loop_label; + locus = other.locus; + // outer_attrs = other.outer_attrs; + + return *this; +} + +LoopExpr::LoopExpr (Analysis::NodeMapping mappings, + std::unique_ptr<BlockExpr> loop_block, location_t locus, + tl::optional<LoopLabel> loop_label, + AST::AttrVec outer_attribs) + : BaseLoopExpr (std::move (mappings), std::move (loop_block), locus, + std::move (loop_label), std::move (outer_attribs)) +{} + +WhileLoopExpr::WhileLoopExpr (Analysis::NodeMapping mappings, + std::unique_ptr<Expr> loop_condition, + std::unique_ptr<BlockExpr> loop_block, + location_t locus, + tl::optional<LoopLabel> loop_label, + AST::AttrVec outer_attribs) + : BaseLoopExpr (std::move (mappings), std::move (loop_block), locus, + std::move (loop_label), std::move (outer_attribs)), + condition (std::move (loop_condition)) +{} + +WhileLoopExpr::WhileLoopExpr (WhileLoopExpr const &other) + : BaseLoopExpr (other), condition (other.condition->clone_expr ()) +{} + +WhileLoopExpr & +WhileLoopExpr::operator= (WhileLoopExpr const &other) +{ + BaseLoopExpr::operator= (other); + condition = other.condition->clone_expr (); + // loop_block = other.loop_block->clone_block_expr(); + // loop_label = other.loop_label; + // outer_attrs = other.outer_attrs; + + return *this; +} + +WhileLetLoopExpr::WhileLetLoopExpr ( + Analysis::NodeMapping mappings, + std::vector<std::unique_ptr<Pattern>> match_arm_patterns, + std::unique_ptr<Expr> condition, std::unique_ptr<BlockExpr> loop_block, + location_t locus, tl::optional<LoopLabel> loop_label, + AST::AttrVec outer_attribs) + : BaseLoopExpr (std::move (mappings), std::move (loop_block), locus, + std::move (loop_label), std::move (outer_attribs)), + match_arm_patterns (std::move (match_arm_patterns)), + condition (std::move (condition)) +{} + +WhileLetLoopExpr::WhileLetLoopExpr (WhileLetLoopExpr const &other) + : BaseLoopExpr (other), + /*match_arm_patterns(other.match_arm_patterns),*/ condition ( + other.condition->clone_expr ()) +{ + match_arm_patterns.reserve (other.match_arm_patterns.size ()); + for (const auto &e : other.match_arm_patterns) + match_arm_patterns.push_back (e->clone_pattern ()); +} + +WhileLetLoopExpr & +WhileLetLoopExpr::operator= (WhileLetLoopExpr const &other) +{ + BaseLoopExpr::operator= (other); + // match_arm_patterns = other.match_arm_patterns; + condition = other.condition->clone_expr (); + // loop_block = other.loop_block->clone_block_expr(); + // loop_label = other.loop_label; + // outer_attrs = other.outer_attrs; + + match_arm_patterns.reserve (other.match_arm_patterns.size ()); + for (const auto &e : other.match_arm_patterns) + match_arm_patterns.push_back (e->clone_pattern ()); + + return *this; +} + +IfExpr::IfExpr (Analysis::NodeMapping mappings, std::unique_ptr<Expr> condition, + std::unique_ptr<BlockExpr> if_block, location_t locus) + : ExprWithBlock (std::move (mappings), AST::AttrVec ()), + condition (std::move (condition)), if_block (std::move (if_block)), + locus (locus) +{} + +IfExpr::IfExpr (IfExpr const &other) + : ExprWithBlock (other), condition (other.condition->clone_expr ()), + if_block (other.if_block->clone_block_expr ()), locus (other.locus) +{} + +IfExpr & +IfExpr::operator= (IfExpr const &other) +{ + ExprWithBlock::operator= (other); + condition = other.condition->clone_expr (); + if_block = other.if_block->clone_block_expr (); + locus = other.locus; + + return *this; +} + +IfExprConseqElse::IfExprConseqElse (Analysis::NodeMapping mappings, + std::unique_ptr<Expr> condition, + std::unique_ptr<BlockExpr> if_block, + std::unique_ptr<ExprWithBlock> else_block, + location_t locus) + : IfExpr (std::move (mappings), std::move (condition), std::move (if_block), + locus), + else_block (std::move (else_block)) +{} + +IfExprConseqElse::IfExprConseqElse (IfExprConseqElse const &other) + : IfExpr (other), else_block (other.else_block->clone_expr_with_block ()) +{} + +IfExprConseqElse & +IfExprConseqElse::operator= (IfExprConseqElse const &other) +{ + IfExpr::operator= (other); + // condition = other.condition->clone_expr(); + // if_block = other.if_block->clone_block_expr(); + else_block = other.else_block->clone_expr_with_block (); + + return *this; +} + +MatchArm::MatchArm (std::vector<std::unique_ptr<Pattern>> match_arm_patterns, + location_t locus, std::unique_ptr<Expr> guard_expr, + AST::AttrVec outer_attrs) + : outer_attrs (std::move (outer_attrs)), + match_arm_patterns (std::move (match_arm_patterns)), + guard_expr (std::move (guard_expr)), locus (locus) +{} + +MatchArm::MatchArm (MatchArm const &other) : outer_attrs (other.outer_attrs) +{ + // guard to protect from null pointer dereference + if (other.guard_expr != nullptr) + guard_expr = other.guard_expr->clone_expr (); + + match_arm_patterns.reserve (other.match_arm_patterns.size ()); + for (const auto &e : other.match_arm_patterns) + match_arm_patterns.push_back (e->clone_pattern ()); + + locus = other.locus; +} + +MatchArm & +MatchArm::operator= (MatchArm const &other) +{ + outer_attrs = other.outer_attrs; + + if (other.guard_expr != nullptr) + guard_expr = other.guard_expr->clone_expr (); + + match_arm_patterns.clear (); + match_arm_patterns.reserve (other.match_arm_patterns.size ()); + for (const auto &e : other.match_arm_patterns) + match_arm_patterns.push_back (e->clone_pattern ()); + + return *this; +} + +MatchCase::MatchCase (Analysis::NodeMapping mappings, MatchArm arm, + std::unique_ptr<Expr> expr) + : mappings (mappings), arm (std::move (arm)), expr (std::move (expr)) +{} + +MatchCase::MatchCase (const MatchCase &other) + : mappings (other.mappings), arm (other.arm), expr (other.expr->clone_expr ()) +{} + +MatchCase & +MatchCase::operator= (const MatchCase &other) +{ + mappings = other.mappings; + arm = other.arm; + expr = other.expr->clone_expr (); + + return *this; +} + +MatchExpr::MatchExpr (Analysis::NodeMapping mappings, + std::unique_ptr<Expr> branch_value, + std::vector<MatchCase> match_arms, + AST::AttrVec inner_attrs, AST::AttrVec outer_attrs, + location_t locus) + : ExprWithBlock (std::move (mappings), std::move (outer_attrs)), + WithInnerAttrs (std::move (inner_attrs)), + branch_value (std::move (branch_value)), + match_arms (std::move (match_arms)), locus (locus) +{} + +MatchExpr::MatchExpr (MatchExpr const &other) + : ExprWithBlock (other), WithInnerAttrs (other.inner_attrs), + branch_value (other.branch_value->clone_expr ()), + match_arms (other.match_arms), locus (other.locus) +{ + /*match_arms.reserve (other.match_arms.size ()); + for (const auto &e : other.match_arms) + match_arms.push_back (e->clone_match_case ());*/ +} + +MatchExpr & +MatchExpr::operator= (MatchExpr const &other) +{ + ExprWithBlock::operator= (other); + branch_value = other.branch_value->clone_expr (); + inner_attrs = other.inner_attrs; + match_arms = other.match_arms; + // outer_attrs = other.outer_attrs; + locus = other.locus; + + /*match_arms.reserve (other.match_arms.size ()); + for (const auto &e : other.match_arms) + match_arms.push_back (e->clone_match_case ());*/ + + return *this; +} + +AwaitExpr::AwaitExpr (Analysis::NodeMapping mappings, + std::unique_ptr<Expr> awaited_expr, + AST::AttrVec outer_attrs, location_t locus) + : ExprWithoutBlock (std::move (mappings), std::move (outer_attrs)), + awaited_expr (std::move (awaited_expr)), locus (locus) +{} + +AwaitExpr::AwaitExpr (AwaitExpr const &other) + : ExprWithoutBlock (other), awaited_expr (other.awaited_expr->clone_expr ()), + locus (other.locus) +{} + +AwaitExpr & +AwaitExpr::operator= (AwaitExpr const &other) +{ + ExprWithoutBlock::operator= (other); + awaited_expr = other.awaited_expr->clone_expr (); + locus = other.locus; + + return *this; +} + +AsyncBlockExpr::AsyncBlockExpr (Analysis::NodeMapping mappings, + std::unique_ptr<BlockExpr> block_expr, + bool has_move, AST::AttrVec outer_attrs, + location_t locus) + : ExprWithBlock (std::move (mappings), std::move (outer_attrs)), + has_move (has_move), block_expr (std::move (block_expr)), locus (locus) +{} + +AsyncBlockExpr::AsyncBlockExpr (AsyncBlockExpr const &other) + : ExprWithBlock (other), has_move (other.has_move), + block_expr (other.block_expr->clone_block_expr ()), locus (other.locus) +{} + +AsyncBlockExpr & +AsyncBlockExpr::operator= (AsyncBlockExpr const &other) +{ + ExprWithBlock::operator= (other); + has_move = other.has_move; + block_expr = other.block_expr->clone_block_expr (); + locus = other.locus; + + return *this; +} + +OperatorExprMeta::OperatorExprMeta (HIR::CompoundAssignmentExpr &expr) + : node_mappings (expr.get_mappings ()), + lvalue_mappings (expr.get_expr ().get_mappings ()), + locus (expr.get_locus ()) +{} + +OperatorExprMeta::OperatorExprMeta (HIR::ArithmeticOrLogicalExpr &expr) + : node_mappings (expr.get_mappings ()), + lvalue_mappings (expr.get_expr ().get_mappings ()), + locus (expr.get_locus ()) +{} + +OperatorExprMeta::OperatorExprMeta (HIR::NegationExpr &expr) + : node_mappings (expr.get_mappings ()), + lvalue_mappings (expr.get_expr ().get_mappings ()), + locus (expr.get_locus ()) +{} + +OperatorExprMeta::OperatorExprMeta (HIR::DereferenceExpr &expr) + : node_mappings (expr.get_mappings ()), + lvalue_mappings (expr.get_expr ().get_mappings ()), + locus (expr.get_locus ()) +{} + +OperatorExprMeta::OperatorExprMeta (HIR::ArrayIndexExpr &expr) + : node_mappings (expr.get_mappings ()), + lvalue_mappings (expr.get_array_expr ().get_mappings ()), + locus (expr.get_locus ()) +{} + +OperatorExprMeta::OperatorExprMeta (HIR::ComparisonExpr &expr) + : node_mappings (expr.get_mappings ()), + lvalue_mappings (expr.get_expr ().get_mappings ()), + locus (expr.get_locus ()) +{} + +AnonConst::AnonConst (NodeId id, std::unique_ptr<Expr> expr) + : id (id), expr (std::move (expr)) +{ + rust_assert (this->expr != nullptr); +} + +AnonConst::AnonConst (const AnonConst &other) +{ + id = other.id; + expr = other.expr->clone_expr (); +} + +AnonConst +AnonConst::operator= (const AnonConst &other) +{ + id = other.id; + expr = other.expr->clone_expr (); + return *this; +} + +InlineAsmOperand::In::In ( + const tl::optional<struct AST::InlineAsmRegOrRegClass> ®, + std::unique_ptr<Expr> expr) + : reg (reg), expr (std::move (expr)) +{ + rust_assert (this->expr != nullptr); +} + +InlineAsmOperand::In::In (const struct In &other) +{ + reg = other.reg; + + expr = other.expr->clone_expr (); +} + +InlineAsmOperand::In +InlineAsmOperand::In::operator= (const struct In &other) +{ + reg = other.reg; + expr = other.expr->clone_expr (); + + return *this; +} + +InlineAsmOperand::Out::Out ( + tl::optional<struct AST::InlineAsmRegOrRegClass> ®, bool late, + std::unique_ptr<Expr> expr) + : reg (reg), late (late), expr (std::move (expr)) +{ + rust_assert (this->expr != nullptr); +} + +InlineAsmOperand::Out::Out (const struct Out &other) +{ + reg = other.reg; + late = other.late; + expr = other.expr->clone_expr (); +} + +InlineAsmOperand::Out +InlineAsmOperand::Out::operator= (const struct Out &other) +{ + reg = other.reg; + late = other.late; + expr = other.expr->clone_expr (); + return *this; +} + +InlineAsmOperand::InOut::InOut ( + tl::optional<struct AST::InlineAsmRegOrRegClass> ®, bool late, + std::unique_ptr<Expr> expr) + : reg (reg), late (late), expr (std::move (expr)) +{ + rust_assert (this->expr != nullptr); +} + +InlineAsmOperand::InOut::InOut (const struct InOut &other) +{ + reg = other.reg; + late = other.late; + expr = other.expr->clone_expr (); +} + +InlineAsmOperand::InOut +InlineAsmOperand::InOut::operator= (const struct InOut &other) +{ + reg = other.reg; + late = other.late; + expr = other.expr->clone_expr (); + + return *this; +} + +InlineAsmOperand::SplitInOut::SplitInOut ( + tl::optional<struct AST::InlineAsmRegOrRegClass> ®, bool late, + std::unique_ptr<Expr> in_expr, std::unique_ptr<Expr> out_expr) + : reg (reg), late (late), in_expr (std::move (in_expr)), + out_expr (std::move (out_expr)) +{ + rust_assert (this->in_expr != nullptr); + rust_assert (this->out_expr != nullptr); +} + +InlineAsmOperand::SplitInOut::SplitInOut (const struct SplitInOut &other) +{ + reg = other.reg; + late = other.late; + in_expr = other.in_expr->clone_expr (); + out_expr = other.out_expr->clone_expr (); +} + +InlineAsmOperand::SplitInOut +InlineAsmOperand::SplitInOut::operator= (const struct SplitInOut &other) +{ + reg = other.reg; + late = other.late; + in_expr = other.in_expr->clone_expr (); + out_expr = other.out_expr->clone_expr (); + + return *this; +} + +InlineAsmOperand::Sym::Sym (std::unique_ptr<Expr> expr) + : expr (std::move (expr)) +{ + rust_assert (this->expr != nullptr); +} + +InlineAsmOperand::Sym::Sym (const struct Sym &other) +{ + expr = std::unique_ptr<Expr> (other.expr->clone_expr ()); +} + +InlineAsmOperand::Sym +InlineAsmOperand::Sym::operator= (const struct Sym &other) +{ + expr = std::unique_ptr<Expr> (other.expr->clone_expr ()); + return *this; +} + +InlineAsmOperand::Label::Label (tl::optional<std::string> label_name, + std::unique_ptr<Expr> expr) + : expr (std::move (expr)) +{ + rust_assert (this->expr != nullptr); + if (label_name.has_value ()) + this->label_name = label_name.value (); +} + +InlineAsmOperand::Label::Label (const struct Label &other) +{ + expr = std::unique_ptr<Expr> (other.expr->clone_expr ()); +} + +InlineAsmOperand::Label +InlineAsmOperand::Label::operator= (const struct Label &other) +{ + expr = std::unique_ptr<Expr> (other.expr->clone_expr ()); + return *this; +} + +InlineAsm::InlineAsm (location_t locus, bool is_global_asm, + std::vector<AST::InlineAsmTemplatePiece> template_, + std::vector<AST::TupleTemplateStr> template_strs, + std::vector<HIR::InlineAsmOperand> operands, + std::vector<AST::TupleClobber> clobber_abi, + std::set<AST::InlineAsmOption> options, + Analysis::NodeMapping mappings, + AST::AttrVec outer_attribs) + : ExprWithoutBlock (std::move (mappings), std::move (outer_attribs)), + locus (locus), is_global_asm (is_global_asm), + template_ (std::move (template_)), + template_strs (std::move (template_strs)), operands (std::move (operands)), + clobber_abi (std::move (clobber_abi)), options (std::move (options)) +{} + +} // namespace HIR +} // namespace Rust diff --git a/gcc/rust/hir/tree/rust-hir-expr.h b/gcc/rust/hir/tree/rust-hir-expr.h index ff9fcee..375f474 100644 --- a/gcc/rust/hir/tree/rust-hir-expr.h +++ b/gcc/rust/hir/tree/rust-hir-expr.h @@ -19,12 +19,13 @@ #ifndef RUST_HIR_EXPR_H #define RUST_HIR_EXPR_H +#include "rust-hir-expr-abstract.h" +#include "rust-hir-literal.h" #include "rust-common.h" -#include "rust-ast-full-decls.h" -#include "rust-hir.h" -#include "rust-hir-path.h" -#include "rust-operators.h" +#include "rust-hir-bound.h" +#include "rust-hir-attrs.h" #include "rust-expr.h" + namespace Rust { namespace HIR { @@ -32,7 +33,7 @@ namespace HIR { // TODO: inline? class LoopLabel /*: public Node*/ { - Lifetime label; // or type LIFETIME_OR_LABEL + Lifetime label; // of type LIFETIME_OR_LABEL location_t locus; @@ -42,12 +43,7 @@ public: std::string as_string () const; LoopLabel (Analysis::NodeMapping mapping, Lifetime loop_label, - location_t locus) - : label (std::move (loop_label)), locus (locus), mappings (mapping) - {} - - // Returns whether the LoopLabel is in an error state. - bool is_error () const { return label.is_error (); } + location_t locus); location_t get_locus () const { return locus; } @@ -62,9 +58,7 @@ class ExprWithBlock : public Expr // TODO: should this mean that a BlockExpr should be a member variable? protected: ExprWithBlock (Analysis::NodeMapping mappings, - AST::AttrVec outer_attrs = AST::AttrVec ()) - : Expr (std::move (mappings), std::move (outer_attrs)) - {} + AST::AttrVec outer_attrs = AST::AttrVec ()); // pure virtual clone implementation virtual ExprWithBlock *clone_expr_with_block_impl () const = 0; @@ -93,6 +87,7 @@ class LiteralExpr : public ExprWithoutBlock { Literal literal; location_t locus; + bool negative_number = false; public: std::string as_string () const override @@ -105,16 +100,10 @@ public: LiteralExpr (Analysis::NodeMapping mappings, std::string value_as_string, Literal::LitType type, PrimitiveCoreType type_hint, - location_t locus, AST::AttrVec outer_attrs) - : ExprWithoutBlock (std::move (mappings), std::move (outer_attrs)), - literal (std::move (value_as_string), type, type_hint), locus (locus) - {} + location_t locus, AST::AttrVec outer_attrs); LiteralExpr (Analysis::NodeMapping mappings, Literal literal, - location_t locus, AST::AttrVec outer_attrs) - : ExprWithoutBlock (std::move (mappings), std::move (outer_attrs)), - literal (std::move (literal)), locus (locus) - {} + location_t locus, AST::AttrVec outer_attrs); // Unique pointer custom clone function std::unique_ptr<LiteralExpr> clone_literal_expr () const @@ -132,6 +121,14 @@ public: ExprType get_expression_type () const override final { return ExprType::Lit; } + bool is_negative () const { return negative_number; } + void set_negative () + { + rust_assert (get_lit_type () == Literal::LitType::INT + || get_lit_type () == Literal::LitType::FLOAT); + negative_number = true; + } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -171,27 +168,13 @@ protected: // Constructor (only for initialisation of expr purposes) OperatorExpr (Analysis::NodeMapping mappings, std::unique_ptr<Expr> main_or_left_expr, - AST::AttrVec outer_attribs, location_t locus) - : ExprWithoutBlock (std::move (mappings), std::move (outer_attribs)), - locus (locus), main_or_left_expr (std::move (main_or_left_expr)) - {} + AST::AttrVec outer_attribs, location_t locus); // Copy constructor (only for initialisation of expr purposes) - OperatorExpr (OperatorExpr const &other) - : ExprWithoutBlock (other), locus (other.locus), - main_or_left_expr (other.main_or_left_expr->clone_expr ()) - {} + OperatorExpr (OperatorExpr const &other); // Overload assignment operator to deep copy expr - OperatorExpr &operator= (OperatorExpr const &other) - { - ExprWithoutBlock::operator= (other); - main_or_left_expr = other.main_or_left_expr->clone_expr (); - locus = other.locus; - // outer_attrs = other.outer_attrs; - - return *this; - } + OperatorExpr &operator= (OperatorExpr const &other); // move constructors OperatorExpr (OperatorExpr &&other) = default; @@ -200,7 +183,7 @@ protected: public: location_t get_locus () const override final { return locus; } - std::unique_ptr<Expr> &get_expr () { return main_or_left_expr; } + Expr &get_expr () { return *main_or_left_expr; } ExprType get_expression_type () const override final { @@ -213,23 +196,21 @@ public: class BorrowExpr : public OperatorExpr { Mutability mut; + bool raw; public: std::string as_string () const override; BorrowExpr (Analysis::NodeMapping mappings, - std::unique_ptr<Expr> borrow_lvalue, Mutability mut, - AST::AttrVec outer_attribs, location_t locus) - : OperatorExpr (std::move (mappings), std::move (borrow_lvalue), - std::move (outer_attribs), locus), - mut (mut) - {} + std::unique_ptr<Expr> borrow_lvalue, Mutability mut, bool raw, + AST::AttrVec outer_attribs, location_t locus); void accept_vis (HIRFullVisitor &vis) override; void accept_vis (HIRExpressionVisitor &vis) override; Mutability get_mut () const { return mut; } bool is_mut () const { return mut == Mutability::Mut; } + bool is_raw_borrow () const { return raw; } protected: /* Use covariance to implement clone function as returning this object rather @@ -256,10 +237,7 @@ public: // Constructor calls OperatorExpr's protected constructor DereferenceExpr (Analysis::NodeMapping mappings, std::unique_ptr<Expr> deref_lvalue, - AST::AttrVec outer_attribs, location_t locus) - : OperatorExpr (std::move (mappings), std::move (deref_lvalue), - std::move (outer_attribs), locus) - {} + AST::AttrVec outer_attribs, location_t locus); void accept_vis (HIRFullVisitor &vis) override; void accept_vis (HIRExpressionVisitor &vis) override; @@ -289,10 +267,7 @@ public: // Constructor calls OperatorExpr's protected constructor ErrorPropagationExpr (Analysis::NodeMapping mappings, std::unique_ptr<Expr> potential_error_value, - AST::AttrVec outer_attribs, location_t locus) - : OperatorExpr (std::move (mappings), std::move (potential_error_value), - std::move (outer_attribs), locus) - {} + AST::AttrVec outer_attribs, location_t locus); void accept_vis (HIRFullVisitor &vis) override; void accept_vis (HIRExpressionVisitor &vis) override; @@ -333,11 +308,7 @@ public: // Constructor calls OperatorExpr's protected constructor NegationExpr (Analysis::NodeMapping mappings, std::unique_ptr<Expr> negated_value, ExprType expr_kind, - AST::AttrVec outer_attribs, location_t locus) - : OperatorExpr (std::move (mappings), std::move (negated_value), - std::move (outer_attribs), locus), - expr_type (expr_kind) - {} + AST::AttrVec outer_attribs, location_t locus); void accept_vis (HIRFullVisitor &vis) override; void accept_vis (HIRExpressionVisitor &vis) override; @@ -379,29 +350,14 @@ public: ArithmeticOrLogicalExpr (Analysis::NodeMapping mappings, std::unique_ptr<Expr> left_value, std::unique_ptr<Expr> right_value, - ExprType expr_kind, location_t locus) - : OperatorExpr (std::move (mappings), std::move (left_value), - AST::AttrVec (), locus), - expr_type (expr_kind), right_expr (std::move (right_value)) - {} + ExprType expr_kind, location_t locus); // outer attributes not allowed // Copy constructor - probably required due to unique pointer - ArithmeticOrLogicalExpr (ArithmeticOrLogicalExpr const &other) - : OperatorExpr (other), expr_type (other.expr_type), - right_expr (other.right_expr->clone_expr ()) - {} + ArithmeticOrLogicalExpr (ArithmeticOrLogicalExpr const &other); // Overload assignment operator - ArithmeticOrLogicalExpr &operator= (ArithmeticOrLogicalExpr const &other) - { - OperatorExpr::operator= (other); - // main_or_left_expr = other.main_or_left_expr->clone_expr(); - right_expr = other.right_expr->clone_expr (); - expr_type = other.expr_type; - - return *this; - } + ArithmeticOrLogicalExpr &operator= (ArithmeticOrLogicalExpr const &other); // move constructors ArithmeticOrLogicalExpr (ArithmeticOrLogicalExpr &&other) = default; @@ -414,8 +370,8 @@ public: void visit_lhs (HIRFullVisitor &vis) { main_or_left_expr->accept_vis (vis); } void visit_rhs (HIRFullVisitor &vis) { right_expr->accept_vis (vis); } - std::unique_ptr<Expr> &get_lhs () { return main_or_left_expr; } - std::unique_ptr<Expr> &get_rhs () { return right_expr; } + Expr &get_lhs () { return *main_or_left_expr; } + Expr &get_rhs () { return *right_expr; } std::string get_operator_str () const; @@ -456,30 +412,14 @@ public: ComparisonExpr (Analysis::NodeMapping mappings, std::unique_ptr<Expr> left_value, std::unique_ptr<Expr> right_value, ExprType comparison_kind, - location_t locus) - : OperatorExpr (std::move (mappings), std::move (left_value), - AST::AttrVec (), locus), - expr_type (comparison_kind), right_expr (std::move (right_value)) - {} + location_t locus); // outer attributes not allowed // Copy constructor also calls OperatorExpr's protected constructor - ComparisonExpr (ComparisonExpr const &other) - : OperatorExpr (other), expr_type (other.expr_type), - right_expr (other.right_expr->clone_expr ()) - {} + ComparisonExpr (ComparisonExpr const &other); // Overload assignment operator to deep copy - ComparisonExpr &operator= (ComparisonExpr const &other) - { - OperatorExpr::operator= (other); - // main_or_left_expr = other.main_or_left_expr->clone_expr(); - right_expr = other.right_expr->clone_expr (); - expr_type = other.expr_type; - // outer_attrs = other.outer_attrs; - - return *this; - } + ComparisonExpr &operator= (ComparisonExpr const &other); // move constructors ComparisonExpr (ComparisonExpr &&other) = default; @@ -488,8 +428,8 @@ public: void accept_vis (HIRFullVisitor &vis) override; void accept_vis (HIRExpressionVisitor &vis) override; - std::unique_ptr<Expr> &get_lhs () { return main_or_left_expr; } - std::unique_ptr<Expr> &get_rhs () { return right_expr; } + Expr &get_lhs () { return *main_or_left_expr; } + Expr &get_rhs () { return *right_expr; } ExprType get_kind () { return expr_type; } @@ -527,29 +467,14 @@ public: LazyBooleanExpr (Analysis::NodeMapping mappings, std::unique_ptr<Expr> left_bool_expr, std::unique_ptr<Expr> right_bool_expr, ExprType expr_kind, - location_t locus) - : OperatorExpr (std::move (mappings), std::move (left_bool_expr), - AST::AttrVec (), locus), - expr_type (expr_kind), right_expr (std::move (right_bool_expr)) - {} + location_t locus); // outer attributes not allowed // Copy constructor also calls OperatorExpr's protected constructor - LazyBooleanExpr (LazyBooleanExpr const &other) - : OperatorExpr (other), expr_type (other.expr_type), - right_expr (other.right_expr->clone_expr ()) - {} + LazyBooleanExpr (LazyBooleanExpr const &other); // Overload assignment operator to deep copy - LazyBooleanExpr &operator= (LazyBooleanExpr const &other) - { - OperatorExpr::operator= (other); - // main_or_left_expr = other.main_or_left_expr->clone_expr(); - right_expr = other.right_expr->clone_expr (); - expr_type = other.expr_type; - - return *this; - } + LazyBooleanExpr &operator= (LazyBooleanExpr const &other); // move constructors LazyBooleanExpr (LazyBooleanExpr &&other) = default; @@ -562,8 +487,8 @@ public: void accept_vis (HIRFullVisitor &vis) override; void accept_vis (HIRExpressionVisitor &vis) override; - std::unique_ptr<Expr> &get_lhs () { return main_or_left_expr; } - std::unique_ptr<Expr> &get_rhs () { return right_expr; } + Expr &get_lhs () { return *main_or_left_expr; } + Expr &get_rhs () { return *right_expr; } protected: /* Use covariance to implement clone function as returning this object rather @@ -593,28 +518,14 @@ public: // Constructor requires calling protected constructor of OperatorExpr TypeCastExpr (Analysis::NodeMapping mappings, std::unique_ptr<Expr> expr_to_cast, - std::unique_ptr<Type> type_to_cast_to, location_t locus) - : OperatorExpr (std::move (mappings), std::move (expr_to_cast), - AST::AttrVec (), locus), - type_to_convert_to (std::move (type_to_cast_to)) - {} + std::unique_ptr<Type> type_to_cast_to, location_t locus); // outer attributes not allowed // Copy constructor also requires calling protected constructor - TypeCastExpr (TypeCastExpr const &other) - : OperatorExpr (other), - type_to_convert_to (other.type_to_convert_to->clone_type ()) - {} + TypeCastExpr (TypeCastExpr const &other); // Overload assignment operator to deep copy - TypeCastExpr &operator= (TypeCastExpr const &other) - { - OperatorExpr::operator= (other); - // main_or_left_expr = other.main_or_left_expr->clone_expr(); - type_to_convert_to = other.type_to_convert_to->clone_type (); - - return *this; - } + TypeCastExpr &operator= (TypeCastExpr const &other); // move constructors as not supported in c++03 TypeCastExpr (TypeCastExpr &&other) = default; @@ -624,12 +535,9 @@ public: void accept_vis (HIRExpressionVisitor &vis) override; // FIXME: isn't it the same as get_expr() from parent? - std::unique_ptr<Expr> &get_casted_expr () { return main_or_left_expr; } + Expr &get_casted_expr () { return *main_or_left_expr; } - std::unique_ptr<Type> &get_type_to_convert_to () - { - return type_to_convert_to; - } + Type &get_type_to_convert_to () { return *type_to_convert_to; } protected: /* Use covariance to implement clone function as returning this object rather @@ -658,28 +566,14 @@ public: // Call OperatorExpr constructor to initialise left_expr AssignmentExpr (Analysis::NodeMapping mappings, std::unique_ptr<Expr> value_to_assign_to, - std::unique_ptr<Expr> value_to_assign, location_t locus) - : OperatorExpr (std::move (mappings), std::move (value_to_assign_to), - AST::AttrVec (), locus), - right_expr (std::move (value_to_assign)) - {} + std::unique_ptr<Expr> value_to_assign, location_t locus); // outer attributes not allowed // Call OperatorExpr constructor in copy constructor, as well as clone - AssignmentExpr (AssignmentExpr const &other) - : OperatorExpr (other), right_expr (other.right_expr->clone_expr ()) - {} + AssignmentExpr (AssignmentExpr const &other); // Overload assignment operator to clone unique_ptr right_expr - AssignmentExpr &operator= (AssignmentExpr const &other) - { - OperatorExpr::operator= (other); - // main_or_left_expr = other.main_or_left_expr->clone_expr(); - right_expr = other.right_expr->clone_expr (); - // outer_attrs = other.outer_attrs; - - return *this; - } + AssignmentExpr &operator= (AssignmentExpr const &other); // move constructors AssignmentExpr (AssignmentExpr &&other) = default; @@ -691,8 +585,8 @@ public: void visit_lhs (HIRFullVisitor &vis) { main_or_left_expr->accept_vis (vis); } void visit_rhs (HIRFullVisitor &vis) { right_expr->accept_vis (vis); } - std::unique_ptr<Expr> &get_lhs () { return main_or_left_expr; } - std::unique_ptr<Expr> &get_rhs () { return right_expr; } + Expr &get_lhs () { return *main_or_left_expr; } + Expr &get_rhs () { return *right_expr; } protected: /* Use covariance to implement clone function as returning this object rather @@ -729,30 +623,14 @@ public: CompoundAssignmentExpr (Analysis::NodeMapping mappings, std::unique_ptr<Expr> value_to_assign_to, std::unique_ptr<Expr> value_to_assign, - ExprType expr_kind, location_t locus) - : OperatorExpr (std::move (mappings), std::move (value_to_assign_to), - AST::AttrVec (), locus), - expr_type (expr_kind), right_expr (std::move (value_to_assign)) - {} + ExprType expr_kind, location_t locus); // outer attributes not allowed // Have clone in copy constructor - CompoundAssignmentExpr (CompoundAssignmentExpr const &other) - : OperatorExpr (other), expr_type (other.expr_type), - right_expr (other.right_expr->clone_expr ()) - {} + CompoundAssignmentExpr (CompoundAssignmentExpr const &other); // Overload assignment operator to clone - CompoundAssignmentExpr &operator= (CompoundAssignmentExpr const &other) - { - OperatorExpr::operator= (other); - // main_or_left_expr = other.main_or_left_expr->clone_expr(); - right_expr = other.right_expr->clone_expr (); - expr_type = other.expr_type; - // outer_attrs = other.outer_attrs; - - return *this; - } + CompoundAssignmentExpr &operator= (CompoundAssignmentExpr const &other); // move constructors CompoundAssignmentExpr (CompoundAssignmentExpr &&other) = default; @@ -761,9 +639,9 @@ public: void accept_vis (HIRFullVisitor &vis) override; void accept_vis (HIRExpressionVisitor &vis) override; - std::unique_ptr<Expr> &get_lhs () { return main_or_left_expr; } + Expr &get_lhs () { return *main_or_left_expr; } - std::unique_ptr<Expr> &get_rhs () { return right_expr; } + Expr &get_rhs () { return *right_expr; } void visit_lhs (HIRFullVisitor &vis) { main_or_left_expr->accept_vis (vis); } void visit_rhs (HIRFullVisitor &vis) { right_expr->accept_vis (vis); } @@ -792,29 +670,13 @@ public: GroupedExpr (Analysis::NodeMapping mappings, std::unique_ptr<Expr> parenthesised_expr, AST::AttrVec inner_attribs, AST::AttrVec outer_attribs, - location_t locus) - : ExprWithoutBlock (std::move (mappings), std::move (outer_attribs)), - WithInnerAttrs (std::move (inner_attribs)), - expr_in_parens (std::move (parenthesised_expr)), locus (locus) - {} + location_t locus); // Copy constructor includes clone for expr_in_parens - GroupedExpr (GroupedExpr const &other) - : ExprWithoutBlock (other), WithInnerAttrs (other.inner_attrs), - expr_in_parens (other.expr_in_parens->clone_expr ()), locus (other.locus) - {} + GroupedExpr (GroupedExpr const &other); // Overloaded assignment operator to clone expr_in_parens - GroupedExpr &operator= (GroupedExpr const &other) - { - ExprWithoutBlock::operator= (other); - inner_attrs = other.inner_attrs; - expr_in_parens = other.expr_in_parens->clone_expr (); - locus = other.locus; - // outer_attrs = other.outer_attrs; - - return *this; - } + GroupedExpr &operator= (GroupedExpr const &other); // move constructors GroupedExpr (GroupedExpr &&other) = default; @@ -825,7 +687,7 @@ public: void accept_vis (HIRFullVisitor &vis) override; void accept_vis (HIRExpressionVisitor &vis) override; - std::unique_ptr<Expr> &get_expr_in_parens () { return expr_in_parens; } + Expr &get_expr_in_parens () { return *expr_in_parens; } ExprType get_expression_type () const override final { @@ -887,33 +749,19 @@ protected: // Value array elements class ArrayElemsValues : public ArrayElems { - std::vector<std::unique_ptr<Expr> > values; + std::vector<std::unique_ptr<Expr>> values; // TODO: should this store location data? public: ArrayElemsValues (Analysis::NodeMapping mappings, - std::vector<std::unique_ptr<Expr> > elems) - : ArrayElems (mappings), values (std::move (elems)) - {} + std::vector<std::unique_ptr<Expr>> elems); // copy constructor with vector clone - ArrayElemsValues (ArrayElemsValues const &other) : ArrayElems (other) - { - values.reserve (other.values.size ()); - for (const auto &e : other.values) - values.push_back (e->clone_expr ()); - } + ArrayElemsValues (ArrayElemsValues const &other); // overloaded assignment operator with vector clone - ArrayElemsValues &operator= (ArrayElemsValues const &other) - { - values.reserve (other.values.size ()); - for (const auto &e : other.values) - values.push_back (e->clone_expr ()); - - return *this; - } + ArrayElemsValues &operator= (ArrayElemsValues const &other); // move constructors ArrayElemsValues (ArrayElemsValues &&other) = default; @@ -925,7 +773,7 @@ public: size_t get_num_elements () const { return values.size (); } - std::vector<std::unique_ptr<Expr> > &get_values () { return values; } + std::vector<std::unique_ptr<Expr>> &get_values () { return values; } ArrayElems::ArrayExprType get_array_expr_type () const override final { @@ -949,25 +797,13 @@ public: // Constructor requires pointers for polymorphism ArrayElemsCopied (Analysis::NodeMapping mappings, std::unique_ptr<Expr> copied_elem, - std::unique_ptr<Expr> copy_amount) - : ArrayElems (mappings), elem_to_copy (std::move (copied_elem)), - num_copies (std::move (copy_amount)) - {} + std::unique_ptr<Expr> copy_amount); // Copy constructor required due to unique_ptr - uses custom clone - ArrayElemsCopied (ArrayElemsCopied const &other) - : ArrayElems (other), elem_to_copy (other.elem_to_copy->clone_expr ()), - num_copies (other.num_copies->clone_expr ()) - {} + ArrayElemsCopied (ArrayElemsCopied const &other); // Overloaded assignment operator for deep copying - ArrayElemsCopied &operator= (ArrayElemsCopied const &other) - { - elem_to_copy = other.elem_to_copy->clone_expr (); - num_copies = other.num_copies->clone_expr (); - - return *this; - } + ArrayElemsCopied &operator= (ArrayElemsCopied const &other); // move constructors ArrayElemsCopied (ArrayElemsCopied &&other) = default; @@ -977,9 +813,9 @@ public: void accept_vis (HIRFullVisitor &vis) override; - std::unique_ptr<Expr> &get_elem_to_copy () { return elem_to_copy; } + Expr &get_elem_to_copy () { return *elem_to_copy; } - std::unique_ptr<Expr> &get_num_copies_expr () { return num_copies; } + Expr &get_num_copies_expr () { return *num_copies; } ArrayElems::ArrayExprType get_array_expr_type () const override final { @@ -1010,33 +846,13 @@ public: ArrayExpr (Analysis::NodeMapping mappings, std::unique_ptr<ArrayElems> array_elems, AST::AttrVec inner_attribs, AST::AttrVec outer_attribs, - location_t locus) - : ExprWithoutBlock (std::move (mappings), std::move (outer_attribs)), - WithInnerAttrs (std::move (inner_attribs)), - internal_elements (std::move (array_elems)), locus (locus) - {} + location_t locus); // Copy constructor requires cloning ArrayElems for polymorphism to hold - ArrayExpr (ArrayExpr const &other) - : ExprWithoutBlock (other), WithInnerAttrs (other.inner_attrs), - locus (other.locus) - { - if (other.has_array_elems ()) - internal_elements = other.internal_elements->clone_array_elems (); - } + ArrayExpr (ArrayExpr const &other); // Overload assignment operator to clone internal_elements - ArrayExpr &operator= (ArrayExpr const &other) - { - ExprWithoutBlock::operator= (other); - inner_attrs = other.inner_attrs; - if (other.has_array_elems ()) - internal_elements = other.internal_elements->clone_array_elems (); - locus = other.locus; - // outer_attrs = other.outer_attrs; - - return *this; - } + ArrayExpr &operator= (ArrayExpr const &other); // move constructors ArrayExpr (ArrayExpr &&other) = default; @@ -1047,10 +863,7 @@ public: void accept_vis (HIRFullVisitor &vis) override; void accept_vis (HIRExpressionVisitor &vis) override; - std::unique_ptr<ArrayElems> &get_internal_elements () - { - return internal_elements; - }; + ArrayElems &get_internal_elements () { return *internal_elements; }; ExprType get_expression_type () const override final { @@ -1083,29 +896,13 @@ public: ArrayIndexExpr (Analysis::NodeMapping mappings, std::unique_ptr<Expr> array_expr, std::unique_ptr<Expr> array_index_expr, - AST::AttrVec outer_attribs, location_t locus) - : ExprWithoutBlock (std::move (mappings), std::move (outer_attribs)), - array_expr (std::move (array_expr)), - index_expr (std::move (array_index_expr)), locus (locus) - {} + AST::AttrVec outer_attribs, location_t locus); // Copy constructor requires special cloning due to unique_ptr - ArrayIndexExpr (ArrayIndexExpr const &other) - : ExprWithoutBlock (other), array_expr (other.array_expr->clone_expr ()), - index_expr (other.index_expr->clone_expr ()), locus (other.locus) - {} + ArrayIndexExpr (ArrayIndexExpr const &other); // Overload assignment operator to clone unique_ptrs - ArrayIndexExpr &operator= (ArrayIndexExpr const &other) - { - ExprWithoutBlock::operator= (other); - array_expr = other.array_expr->clone_expr (); - index_expr = other.index_expr->clone_expr (); - // outer_attrs = other.outer_attrs; - locus = other.locus; - - return *this; - } + ArrayIndexExpr &operator= (ArrayIndexExpr const &other); // move constructors ArrayIndexExpr (ArrayIndexExpr &&other) = default; @@ -1116,8 +913,8 @@ public: void accept_vis (HIRFullVisitor &vis) override; void accept_vis (HIRExpressionVisitor &vis) override; - std::unique_ptr<Expr> &get_array_expr () { return array_expr; } - std::unique_ptr<Expr> &get_index_expr () { return index_expr; } + Expr &get_array_expr () { return *array_expr; } + Expr &get_index_expr () { return *index_expr; } ExprType get_expression_type () const override final { @@ -1143,7 +940,7 @@ protected: // HIR representation of a tuple class TupleExpr : public ExprWithoutBlock, public WithInnerAttrs { - std::vector<std::unique_ptr<Expr> > tuple_elems; + std::vector<std::unique_ptr<Expr>> tuple_elems; // replaces (inlined version of) TupleElements location_t locus; @@ -1152,37 +949,15 @@ public: std::string as_string () const override; TupleExpr (Analysis::NodeMapping mappings, - std::vector<std::unique_ptr<Expr> > tuple_elements, + std::vector<std::unique_ptr<Expr>> tuple_elements, AST::AttrVec inner_attribs, AST::AttrVec outer_attribs, - location_t locus) - : ExprWithoutBlock (std::move (mappings), std::move (outer_attribs)), - WithInnerAttrs (std::move (inner_attribs)), - tuple_elems (std::move (tuple_elements)), locus (locus) - {} + location_t locus); // copy constructor with vector clone - TupleExpr (TupleExpr const &other) - : ExprWithoutBlock (other), WithInnerAttrs (other.inner_attrs), - locus (other.locus) - { - tuple_elems.reserve (other.tuple_elems.size ()); - for (const auto &e : other.tuple_elems) - tuple_elems.push_back (e->clone_expr ()); - } + TupleExpr (TupleExpr const &other); // overloaded assignment operator to vector clone - TupleExpr &operator= (TupleExpr const &other) - { - ExprWithoutBlock::operator= (other); - inner_attrs = other.inner_attrs; - locus = other.locus; - - tuple_elems.reserve (other.tuple_elems.size ()); - for (const auto &e : other.tuple_elems) - tuple_elems.push_back (e->clone_expr ()); - - return *this; - } + TupleExpr &operator= (TupleExpr const &other); // move constructors TupleExpr (TupleExpr &&other) = default; @@ -1196,14 +971,11 @@ public: void accept_vis (HIRFullVisitor &vis) override; void accept_vis (HIRExpressionVisitor &vis) override; - const std::vector<std::unique_ptr<Expr> > &get_tuple_elems () const - { - return tuple_elems; - } - std::vector<std::unique_ptr<Expr> > &get_tuple_elems () + const std::vector<std::unique_ptr<Expr>> &get_tuple_elems () const { return tuple_elems; } + std::vector<std::unique_ptr<Expr>> &get_tuple_elems () { return tuple_elems; } bool is_unit () const { return tuple_elems.size () == 0; } @@ -1238,28 +1010,13 @@ public: TupleIndexExpr (Analysis::NodeMapping mappings, std::unique_ptr<Expr> tuple_expr, TupleIndex index, - AST::AttrVec outer_attribs, location_t locus) - : ExprWithoutBlock (std::move (mappings), std::move (outer_attribs)), - tuple_expr (std::move (tuple_expr)), tuple_index (index), locus (locus) - {} + AST::AttrVec outer_attribs, location_t locus); // Copy constructor requires a clone for tuple_expr - TupleIndexExpr (TupleIndexExpr const &other) - : ExprWithoutBlock (other), tuple_expr (other.tuple_expr->clone_expr ()), - tuple_index (other.tuple_index), locus (other.locus) - {} + TupleIndexExpr (TupleIndexExpr const &other); // Overload assignment operator in order to clone - TupleIndexExpr &operator= (TupleIndexExpr const &other) - { - ExprWithoutBlock::operator= (other); - tuple_expr = other.tuple_expr->clone_expr (); - tuple_index = other.tuple_index; - locus = other.locus; - // outer_attrs = other.outer_attrs; - - return *this; - } + TupleIndexExpr &operator= (TupleIndexExpr const &other); // move constructors TupleIndexExpr (TupleIndexExpr &&other) = default; @@ -1270,7 +1027,7 @@ public: void accept_vis (HIRFullVisitor &vis) override; void accept_vis (HIRExpressionVisitor &vis) override; - std::unique_ptr<Expr> &get_tuple_expr () { return tuple_expr; } + Expr &get_tuple_expr () { return *tuple_expr; } ExprType get_expression_type () const override final { @@ -1301,10 +1058,7 @@ protected: // Protected constructor to allow initialising struct_name StructExpr (Analysis::NodeMapping mappings, PathInExpression struct_path, - AST::AttrVec outer_attribs) - : ExprWithoutBlock (std::move (mappings), std::move (outer_attribs)), - struct_name (std::move (struct_path)) - {} + AST::AttrVec outer_attribs); public: PathInExpression &get_struct_name () { return struct_name; } @@ -1328,11 +1082,7 @@ public: // Constructor has to call protected constructor of base class StructExprStruct (Analysis::NodeMapping mappings, PathInExpression struct_path, AST::AttrVec inner_attribs, - AST::AttrVec outer_attribs, location_t locus) - : StructExpr (std::move (mappings), std::move (struct_path), - std::move (outer_attribs)), - WithInnerAttrs (std::move (inner_attribs)), locus (locus) - {} + AST::AttrVec outer_attribs, location_t locus); location_t get_locus () const override final { return locus; } @@ -1359,33 +1109,21 @@ protected: * struct */ struct StructBase { -public: +private: std::unique_ptr<Expr> base_struct; +public: // TODO: should this store location data? - StructBase (std::unique_ptr<Expr> base_struct_ptr) - : base_struct (std::move (base_struct_ptr)) - {} + StructBase (std::unique_ptr<Expr> base_struct_ptr); // Copy constructor requires clone - StructBase (StructBase const &other) - { - /* HACK: gets around base_struct pointer being null (e.g. if no struct base - * exists) */ - if (other.base_struct != nullptr) - other.base_struct->clone_expr (); - } + StructBase (StructBase const &other); // Destructor ~StructBase () = default; // Overload assignment operator to clone base_struct - StructBase &operator= (StructBase const &other) - { - base_struct = other.base_struct->clone_expr (); - - return *this; - } + StructBase &operator= (StructBase const &other); // move constructors StructBase (StructBase &&other) = default; @@ -1399,7 +1137,7 @@ public: std::string as_string () const; - Expr *get_base () { return base_struct.get (); } + Expr &get_base () { return *base_struct; } }; /* Base HIR node for a single struct expression field (in struct instance @@ -1437,9 +1175,7 @@ protected: // pure virtual clone implementation virtual StructExprField *clone_struct_expr_field_impl () const = 0; - StructExprField (Analysis::NodeMapping mapping, location_t locus) - : mappings (mapping), locus (locus) - {} + StructExprField (Analysis::NodeMapping mapping, location_t locus); Analysis::NodeMapping mappings; location_t locus; @@ -1454,10 +1190,7 @@ private: // TODO: should this store location data? public: StructExprFieldIdentifier (Analysis::NodeMapping mapping, - Identifier field_identifier, location_t locus) - : StructExprField (mapping, locus), - field_name (std::move (field_identifier)) - {} + Identifier field_identifier, location_t locus); std::string as_string () const override { return field_name.as_string (); } @@ -1488,25 +1221,13 @@ class StructExprFieldWithVal : public StructExprField protected: StructExprFieldWithVal (Analysis::NodeMapping mapping, - std::unique_ptr<Expr> field_value, location_t locus) - : StructExprField (mapping, locus), value (std::move (field_value)) - {} + std::unique_ptr<Expr> field_value, location_t locus); // Copy constructor requires clone - StructExprFieldWithVal (StructExprFieldWithVal const &other) - : StructExprField (other.mappings, other.locus), - value (other.value->clone_expr ()) - {} + StructExprFieldWithVal (StructExprFieldWithVal const &other); // Overload assignment operator to clone unique_ptr - StructExprFieldWithVal &operator= (StructExprFieldWithVal const &other) - { - value = other.value->clone_expr (); - mappings = other.mappings; - locus = other.locus; - - return *this; - } + StructExprFieldWithVal &operator= (StructExprFieldWithVal const &other); // move constructors StructExprFieldWithVal (StructExprFieldWithVal &&other) = default; @@ -1515,7 +1236,7 @@ protected: public: std::string as_string () const override; - std::unique_ptr<Expr> &get_value () { return value; } + Expr &get_value () { return *value; } }; // Identifier and value variant of StructExprField HIR node @@ -1529,10 +1250,7 @@ public: StructExprFieldIdentifierValue (Analysis::NodeMapping mapping, Identifier field_identifier, std::unique_ptr<Expr> field_value, - location_t locus) - : StructExprFieldWithVal (mapping, std::move (field_value), locus), - field_name (std::move (field_identifier)) - {} + location_t locus); std::string as_string () const override; @@ -1566,10 +1284,7 @@ public: StructExprFieldIndexValue (Analysis::NodeMapping mapping, TupleIndex tuple_index, std::unique_ptr<Expr> field_value, - location_t locus) - : StructExprFieldWithVal (mapping, std::move (field_value), locus), - index (tuple_index) - {} + location_t locus); std::string as_string () const override; @@ -1595,58 +1310,31 @@ protected: // HIR node of a struct creator with fields class StructExprStructFields : public StructExprStruct { -public: // std::vector<StructExprField> fields; - std::vector<std::unique_ptr<StructExprField> > fields; - - // bool has_struct_base; - // FIXME make unique_ptr - StructBase *struct_base; + std::vector<std::unique_ptr<StructExprField>> fields; + tl::optional<std::unique_ptr<StructBase>> struct_base; +public: // For unions there is just one field, the index // is set when type checking int union_index = -1; std::string as_string () const override; - bool has_struct_base () const { return struct_base != nullptr; } + bool has_struct_base () const { return struct_base.has_value (); } // Constructor for StructExprStructFields when no struct base is used StructExprStructFields ( Analysis::NodeMapping mappings, PathInExpression struct_path, - std::vector<std::unique_ptr<StructExprField> > expr_fields, - location_t locus, StructBase *base_struct, - AST::AttrVec inner_attribs = AST::AttrVec (), - AST::AttrVec outer_attribs = AST::AttrVec ()) - : StructExprStruct (std::move (mappings), std::move (struct_path), - std::move (inner_attribs), std::move (outer_attribs), - locus), - fields (std::move (expr_fields)), struct_base (base_struct) - {} + std::vector<std::unique_ptr<StructExprField>> expr_fields, location_t locus, + tl::optional<std::unique_ptr<StructBase>> base_struct, + AST::AttrVec inner_attribs, AST::AttrVec outer_attribs); // copy constructor with vector clone - StructExprStructFields (StructExprStructFields const &other) - : StructExprStruct (other), struct_base (other.struct_base), - union_index (other.union_index) - { - fields.reserve (other.fields.size ()); - for (const auto &e : other.fields) - fields.push_back (e->clone_struct_expr_field ()); - } + StructExprStructFields (StructExprStructFields const &other); // overloaded assignment operator with vector clone - StructExprStructFields &operator= (StructExprStructFields const &other) - { - StructExprStruct::operator= (other); - struct_base = other.struct_base; - union_index = other.union_index; - - fields.reserve (other.fields.size ()); - for (const auto &e : other.fields) - fields.push_back (e->clone_struct_expr_field ()); - - return *this; - } + StructExprStructFields &operator= (StructExprStructFields const &other); // move constructors StructExprStructFields (StructExprStructFields &&other) = default; @@ -1655,20 +1343,20 @@ public: void accept_vis (HIRFullVisitor &vis) override; void accept_vis (HIRExpressionVisitor &vis) override; - std::vector<std::unique_ptr<StructExprField> > &get_fields () + std::vector<std::unique_ptr<StructExprField>> &get_fields () { return fields; }; - const std::vector<std::unique_ptr<StructExprField> > &get_fields () const + const std::vector<std::unique_ptr<StructExprField>> &get_fields () const { return fields; }; - StructBase *get_struct_base () { return struct_base; } + StructBase &get_struct_base () { return *struct_base.value (); } - void set_fields_as_owner ( - std::vector<std::unique_ptr<StructExprField> > new_fields) + void + set_fields_as_owner (std::vector<std::unique_ptr<StructExprField>> new_fields) { fields = std::move (new_fields); } @@ -1695,26 +1383,15 @@ class StructExprStructBase : public StructExprStruct StructBase struct_base; public: - std::string as_string () const override; - - /*inline StructBase get_struct_base() const { - return struct_base; - }*/ - StructExprStructBase (Analysis::NodeMapping mappings, PathInExpression struct_path, StructBase base_struct, AST::AttrVec inner_attribs, AST::AttrVec outer_attribs, - location_t locus) - : StructExprStruct (std::move (mappings), std::move (struct_path), - std::move (inner_attribs), std::move (outer_attribs), - locus), - struct_base (std::move (base_struct)) - {} + location_t locus); void accept_vis (HIRFullVisitor &vis) override; void accept_vis (HIRExpressionVisitor &vis) override; - StructBase *get_struct_base () { return &struct_base; } + StructBase &get_struct_base () { return struct_base; } protected: /* Use covariance to implement clone function as returning this object rather @@ -1736,45 +1413,21 @@ protected: class CallExpr : public ExprWithoutBlock { std::unique_ptr<Expr> function; - std::vector<std::unique_ptr<Expr> > params; + std::vector<std::unique_ptr<Expr>> params; location_t locus; public: std::string as_string () const override; CallExpr (Analysis::NodeMapping mappings, std::unique_ptr<Expr> function_expr, - std::vector<std::unique_ptr<Expr> > function_params, - AST::AttrVec outer_attribs, location_t locus) - : ExprWithoutBlock (std::move (mappings), std::move (outer_attribs)), - function (std::move (function_expr)), - params (std::move (function_params)), locus (locus) - {} + std::vector<std::unique_ptr<Expr>> function_params, + AST::AttrVec outer_attribs, location_t locus); // copy constructor requires clone - CallExpr (CallExpr const &other) - : ExprWithoutBlock (other), function (other.function->clone_expr ()), - locus (other.locus) - /*, params(other.params),*/ { - params.reserve (other.params.size ()); - for (const auto &e : other.params) - params.push_back (e->clone_expr ()); - } + CallExpr (CallExpr const &other); // Overload assignment operator to clone - CallExpr &operator= (CallExpr const &other) - { - ExprWithoutBlock::operator= (other); - function = other.function->clone_expr (); - locus = other.locus; - // params = other.params; - // outer_attrs = other.outer_attrs; - - params.reserve (other.params.size ()); - for (const auto &e : other.params) - params.push_back (e->clone_expr ()); - - return *this; - } + CallExpr &operator= (CallExpr const &other); // move constructors CallExpr (CallExpr &&other) = default; @@ -1788,13 +1441,14 @@ public: void accept_vis (HIRFullVisitor &vis) override; void accept_vis (HIRExpressionVisitor &vis) override; - std::unique_ptr<Expr> &get_fnexpr () { return function; } + bool has_fnexpr () const { return function != nullptr; } + Expr &get_fnexpr () { return *function; } size_t num_params () const { return params.size (); } - std::vector<std::unique_ptr<Expr> > &get_arguments () { return params; } + std::vector<std::unique_ptr<Expr>> &get_arguments () { return params; } - const std::vector<std::unique_ptr<Expr> > &get_arguments () const + const std::vector<std::unique_ptr<Expr>> &get_arguments () const { return params; } @@ -1822,7 +1476,7 @@ class MethodCallExpr : public ExprWithoutBlock { std::unique_ptr<Expr> receiver; PathExprSegment method_name; - std::vector<std::unique_ptr<Expr> > params; + std::vector<std::unique_ptr<Expr>> params; location_t locus; public: @@ -1831,40 +1485,14 @@ public: MethodCallExpr (Analysis::NodeMapping mappings, std::unique_ptr<Expr> call_receiver, PathExprSegment method_path, - std::vector<std::unique_ptr<Expr> > method_params, - AST::AttrVec outer_attribs, location_t locus) - : ExprWithoutBlock (std::move (mappings), std::move (outer_attribs)), - receiver (std::move (call_receiver)), - method_name (std::move (method_path)), params (std::move (method_params)), - locus (locus) - {} + std::vector<std::unique_ptr<Expr>> method_params, + AST::AttrVec outer_attribs, location_t locus); // copy constructor required due to cloning - MethodCallExpr (MethodCallExpr const &other) - : ExprWithoutBlock (other), receiver (other.receiver->clone_expr ()), - method_name (other.method_name), locus (other.locus) - /*, params(other.params),*/ { - params.reserve (other.params.size ()); - for (const auto &e : other.params) - params.push_back (e->clone_expr ()); - } + MethodCallExpr (MethodCallExpr const &other); // Overload assignment operator to clone receiver object - MethodCallExpr &operator= (MethodCallExpr const &other) - { - ExprWithoutBlock::operator= (other); - receiver = other.receiver->clone_expr (); - method_name = other.method_name; - locus = other.locus; - // params = other.params; - // outer_attrs = other.outer_attrs; - - params.reserve (other.params.size ()); - for (const auto &e : other.params) - params.push_back (e->clone_expr ()); - - return *this; - } + MethodCallExpr &operator= (MethodCallExpr const &other); // move constructors MethodCallExpr (MethodCallExpr &&other) = default; @@ -1875,7 +1503,7 @@ public: void accept_vis (HIRFullVisitor &vis) override; void accept_vis (HIRExpressionVisitor &vis) override; - std::unique_ptr<Expr> &get_receiver () { return receiver; } + Expr &get_receiver () { return *receiver; } PathExprSegment &get_method_name () { return method_name; }; const PathExprSegment &get_method_name () const { return method_name; }; @@ -1883,9 +1511,9 @@ public: bool has_params () const { return !params.empty (); } size_t num_params () const { return params.size (); } - std::vector<std::unique_ptr<Expr> > &get_arguments () { return params; } + std::vector<std::unique_ptr<Expr>> &get_arguments () { return params; } - const std::vector<std::unique_ptr<Expr> > &get_arguments () const + const std::vector<std::unique_ptr<Expr>> &get_arguments () const { return params; } @@ -1926,29 +1554,13 @@ public: FieldAccessExpr (Analysis::NodeMapping mappings, std::unique_ptr<Expr> field_access_receiver, Identifier field_name, AST::AttrVec outer_attribs, - location_t locus) - : ExprWithoutBlock (std::move (mappings), std::move (outer_attribs)), - receiver (std::move (field_access_receiver)), - field (std::move (field_name)), locus (locus) - {} + location_t locus); // Copy constructor required due to unique_ptr cloning - FieldAccessExpr (FieldAccessExpr const &other) - : ExprWithoutBlock (other), receiver (other.receiver->clone_expr ()), - field (other.field), locus (other.locus) - {} + FieldAccessExpr (FieldAccessExpr const &other); // Overload assignment operator to clone unique_ptr - FieldAccessExpr &operator= (FieldAccessExpr const &other) - { - ExprWithoutBlock::operator= (other); - receiver = other.receiver->clone_expr (); - field = other.field; - locus = other.locus; - // outer_attrs = other.outer_attrs; - - return *this; - } + FieldAccessExpr &operator= (FieldAccessExpr const &other); // move constructors FieldAccessExpr (FieldAccessExpr &&other) = default; @@ -1959,7 +1571,7 @@ public: void accept_vis (HIRFullVisitor &vis) override; void accept_vis (HIRExpressionVisitor &vis) override; - std::unique_ptr<Expr> &get_receiver_expr () { return receiver; } + Expr &get_receiver_expr () { return *receiver; } Identifier get_field_name () const { return field; } @@ -2000,42 +1612,15 @@ public: // Constructor for closure parameter ClosureParam (std::unique_ptr<Pattern> param_pattern, location_t locus, std::unique_ptr<Type> param_type = nullptr, - std::vector<AST::Attribute> outer_attrs = {}) - : outer_attrs (std::move (outer_attrs)), - pattern (std::move (param_pattern)), type (std::move (param_type)), - locus (locus) - {} + std::vector<AST::Attribute> outer_attrs = {}); // Copy constructor required due to cloning as a result of unique_ptrs - ClosureParam (ClosureParam const &other) - : pattern (other.pattern->clone_pattern ()) - { - // guard to protect from null pointer dereference - if (other.pattern != nullptr) - pattern = other.pattern->clone_pattern (); - if (other.type != nullptr) - type = other.type->clone_type (); - } + ClosureParam (ClosureParam const &other); ~ClosureParam () = default; // Assignment operator must be overloaded to clone as well - ClosureParam &operator= (ClosureParam const &other) - { - outer_attrs = other.outer_attrs; - - // guard to protect from null pointer dereference - if (other.pattern != nullptr) - pattern = other.pattern->clone_pattern (); - else - pattern = nullptr; - if (other.type != nullptr) - type = other.type->clone_type (); - else - type = nullptr; - - return *this; - } + ClosureParam &operator= (ClosureParam const &other); // move constructors ClosureParam (ClosureParam &&other) = default; @@ -2049,9 +1634,9 @@ public: } std::vector<AST::Attribute> &get_outer_attrs () { return outer_attrs; } - std::unique_ptr<Pattern> &get_pattern () { return pattern; } + Pattern &get_pattern () { return *pattern; } - std::unique_ptr<Type> &get_type () { return type; } + Type &get_type () { return *type; } location_t get_locus () const { return locus; } }; @@ -2071,36 +1656,13 @@ public: std::vector<ClosureParam> closure_params, std::unique_ptr<Type> closure_return_type, std::unique_ptr<Expr> closure_expr, bool has_move, - AST::AttrVec outer_attribs, location_t locus) - : ExprWithoutBlock (std::move (mappings), std::move (outer_attribs)), - has_move (has_move), params (std::move (closure_params)), locus (locus), - return_type (std::move (closure_return_type)), - expr (std::move (closure_expr)) - {} + AST::AttrVec outer_attribs, location_t locus); // Copy constructor requires cloning - ClosureExpr (ClosureExpr const &other) - : ExprWithoutBlock (other.get_mappings (), other.get_outer_attrs ()) - { - return_type - = other.has_return_type () ? other.return_type->clone_type () : nullptr; - expr = other.expr->clone_expr (); - params = other.params; - has_move = other.has_move; - } + ClosureExpr (ClosureExpr const &other); // Overload assignment operator to clone unique_ptrs - ClosureExpr &operator= (ClosureExpr const &other) - { - mappings = other.mappings; - return_type - = other.has_return_type () ? other.return_type->clone_type () : nullptr; - expr = other.expr->clone_expr (); - params = other.params; - has_move = other.has_move; - - return *this; - } + ClosureExpr &operator= (ClosureExpr const &other); // move constructors ClosureExpr (ClosureExpr &&other) = default; @@ -2119,8 +1681,8 @@ public: bool has_return_type () const { return return_type != nullptr; } - std::unique_ptr<Type> &get_return_type () { return return_type; }; - std::unique_ptr<Expr> &get_expr () { return expr; } + Type &get_return_type () { return *return_type; }; + Expr &get_expr () { return *expr; } bool has_params () const { return !params.empty (); } std::vector<ClosureParam> &get_params () { return params; } @@ -2149,10 +1711,10 @@ class BlockExpr : public ExprWithBlock, public WithInnerAttrs { // FIXME this should be private + get/set public: - std::vector<std::unique_ptr<Stmt> > statements; + std::vector<std::unique_ptr<Stmt>> statements; std::unique_ptr<Expr> expr; bool tail_reachable; - LoopLabel label; + tl::optional<LoopLabel> label; location_t start_locus; location_t end_locus; @@ -2169,49 +1731,17 @@ public: bool is_tail_reachable () const { return tail_reachable; } BlockExpr (Analysis::NodeMapping mappings, - std::vector<std::unique_ptr<Stmt> > block_statements, + std::vector<std::unique_ptr<Stmt>> block_statements, std::unique_ptr<Expr> block_expr, bool tail_reachable, AST::AttrVec inner_attribs, AST::AttrVec outer_attribs, - LoopLabel label, location_t start_locus, location_t end_locus) - : ExprWithBlock (std::move (mappings), std::move (outer_attribs)), - WithInnerAttrs (std::move (inner_attribs)), - statements (std::move (block_statements)), expr (std::move (block_expr)), - tail_reachable (tail_reachable), label (std::move (label)), - start_locus (start_locus), end_locus (end_locus) - {} + tl::optional<LoopLabel> label, location_t start_locus, + location_t end_locus); // Copy constructor with clone - BlockExpr (BlockExpr const &other) - : ExprWithBlock (other), /*statements(other.statements),*/ - WithInnerAttrs (other.inner_attrs), label (other.label), - start_locus (other.start_locus), end_locus (other.end_locus) - { - // guard to protect from null pointer dereference - if (other.expr != nullptr) - expr = other.expr->clone_expr (); - - statements.reserve (other.statements.size ()); - for (const auto &e : other.statements) - statements.push_back (e->clone_stmt ()); - } + BlockExpr (BlockExpr const &other); // Overloaded assignment operator to clone pointer - BlockExpr &operator= (BlockExpr const &other) - { - ExprWithBlock::operator= (other); - // statements = other.statements; - expr = other.expr->clone_expr (); - inner_attrs = other.inner_attrs; - start_locus = other.end_locus; - end_locus = other.end_locus; - // outer_attrs = other.outer_attrs; - - statements.reserve (other.statements.size ()); - for (const auto &e : other.statements) - statements.push_back (e->clone_stmt ()); - - return *this; - } + BlockExpr &operator= (BlockExpr const &other); // move constructors BlockExpr (BlockExpr &&other) = default; @@ -2234,17 +1764,18 @@ public: bool is_final_stmt (Stmt *stmt) { return statements.back ().get () == stmt; } - std::unique_ptr<Expr> &get_final_expr () { return expr; } + bool has_final_expr () { return expr != nullptr; } + Expr &get_final_expr () { return *expr; } - std::vector<std::unique_ptr<Stmt> > &get_statements () { return statements; } + std::vector<std::unique_ptr<Stmt>> &get_statements () { return statements; } ExprType get_expression_type () const final override { return ExprType::Block; } - bool has_label () const { return !label.is_error (); } - LoopLabel &get_label () { return label; } + bool has_label () const { return label.has_value (); } + LoopLabel &get_label () { return label.value (); } protected: /* Use covariance to implement clone function as returning this object rather @@ -2272,28 +1803,27 @@ protected: // HIR node representing continue expression within loops class ContinueExpr : public ExprWithoutBlock { - Lifetime label; + tl::optional<Lifetime> label; location_t locus; public: std::string as_string () const override; // Returns true if the continue expr has a label. - bool has_label () const { return !label.is_error (); } + bool has_label () const { return label.has_value (); } // Constructor for a ContinueExpr with a label. ContinueExpr (Analysis::NodeMapping mappings, location_t locus, - Lifetime label, AST::AttrVec outer_attribs = AST::AttrVec ()) - : ExprWithoutBlock (std::move (mappings), std::move (outer_attribs)), - label (std::move (label)), locus (locus) - {} + tl::optional<Lifetime> label, + AST::AttrVec outer_attribs = AST::AttrVec ()); location_t get_locus () const override final { return locus; } void accept_vis (HIRFullVisitor &vis) override; void accept_vis (HIRExpressionVisitor &vis) override; - Lifetime &get_label () { return label; } + Lifetime &get_label () { return label.value (); } + const Lifetime &get_label () const { return label.value (); } ExprType get_expression_type () const final override { @@ -2320,7 +1850,7 @@ protected: class BreakExpr : public ExprWithoutBlock { // bool has_label; - Lifetime label; + tl::optional<Lifetime> label; // bool has_break_expr; std::unique_ptr<Expr> break_expr; @@ -2331,7 +1861,7 @@ public: std::string as_string () const override; // Returns whether the break expression has a label or not. - bool has_label () const { return !label.is_error (); } + bool has_label () const { return label.has_value (); } /* Returns whether the break expression has an expression used in the break or * not. */ @@ -2339,34 +1869,15 @@ public: // Constructor for a break expression BreakExpr (Analysis::NodeMapping mappings, location_t locus, - Lifetime break_label, + tl::optional<Lifetime> break_label, std::unique_ptr<Expr> expr_in_break = nullptr, - AST::AttrVec outer_attribs = AST::AttrVec ()) - : ExprWithoutBlock (std::move (mappings), std::move (outer_attribs)), - label (std::move (break_label)), break_expr (std::move (expr_in_break)), - locus (locus) - {} + AST::AttrVec outer_attribs = AST::AttrVec ()); // Copy constructor defined to use clone for unique pointer - BreakExpr (BreakExpr const &other) - : ExprWithoutBlock (other), label (other.label), locus (other.locus) - { - // guard to protect from null pointer dereference - if (other.break_expr != nullptr) - break_expr = other.break_expr->clone_expr (); - } + BreakExpr (BreakExpr const &other); // Overload assignment operator to clone unique pointer - BreakExpr &operator= (BreakExpr const &other) - { - ExprWithoutBlock::operator= (other); - label = other.label; - break_expr = other.break_expr->clone_expr (); - locus = other.locus; - // outer_attrs = other.outer_attrs; - - return *this; - } + BreakExpr &operator= (BreakExpr const &other); // move constructors BreakExpr (BreakExpr &&other) = default; @@ -2377,9 +1888,10 @@ public: void accept_vis (HIRFullVisitor &vis) override; void accept_vis (HIRExpressionVisitor &vis) override; - Lifetime &get_label () { return label; } + Lifetime &get_label () { return label.value (); } + const Lifetime &get_label () const { return label.value (); } - std::unique_ptr<Expr> &get_expr () { return break_expr; } + Expr &get_expr () { return *break_expr; } ExprType get_expression_type () const override final { @@ -2406,9 +1918,7 @@ class RangeExpr : public ExprWithoutBlock protected: // outer attributes not allowed before range expressions - RangeExpr (Analysis::NodeMapping mappings, location_t locus) - : ExprWithoutBlock (std::move (mappings), AST::AttrVec ()), locus (locus) - {} + RangeExpr (Analysis::NodeMapping mappings, location_t locus); public: location_t get_locus () const override final { return locus; } @@ -2431,26 +1941,13 @@ public: RangeFromToExpr (Analysis::NodeMapping mappings, std::unique_ptr<Expr> range_from, - std::unique_ptr<Expr> range_to, location_t locus) - : RangeExpr (std::move (mappings), locus), from (std::move (range_from)), - to (std::move (range_to)) - {} + std::unique_ptr<Expr> range_to, location_t locus); // Copy constructor with cloning - RangeFromToExpr (RangeFromToExpr const &other) - : RangeExpr (other), from (other.from->clone_expr ()), - to (other.to->clone_expr ()) - {} + RangeFromToExpr (RangeFromToExpr const &other); // Overload assignment operator to clone unique pointers - RangeFromToExpr &operator= (RangeFromToExpr const &other) - { - RangeExpr::operator= (other); - from = other.from->clone_expr (); - to = other.to->clone_expr (); - - return *this; - } + RangeFromToExpr &operator= (RangeFromToExpr const &other); // move constructors RangeFromToExpr (RangeFromToExpr &&other) = default; @@ -2459,8 +1956,8 @@ public: void accept_vis (HIRFullVisitor &vis) override; void accept_vis (HIRExpressionVisitor &vis) override; - std::unique_ptr<Expr> &get_from_expr () { return from; } - std::unique_ptr<Expr> &get_to_expr () { return to; } + Expr &get_from_expr () { return *from; } + Expr &get_to_expr () { return *to; } protected: /* Use covariance to implement clone function as returning this object rather @@ -2488,23 +1985,13 @@ public: std::string as_string () const override; RangeFromExpr (Analysis::NodeMapping mappings, - std::unique_ptr<Expr> range_from, location_t locus) - : RangeExpr (std::move (mappings), locus), from (std::move (range_from)) - {} + std::unique_ptr<Expr> range_from, location_t locus); // Copy constructor with clone - RangeFromExpr (RangeFromExpr const &other) - : RangeExpr (other), from (other.from->clone_expr ()) - {} + RangeFromExpr (RangeFromExpr const &other); // Overload assignment operator to clone unique_ptr - RangeFromExpr &operator= (RangeFromExpr const &other) - { - RangeExpr::operator= (other); - from = other.from->clone_expr (); - - return *this; - } + RangeFromExpr &operator= (RangeFromExpr const &other); // move constructors RangeFromExpr (RangeFromExpr &&other) = default; @@ -2513,7 +2000,7 @@ public: void accept_vis (HIRFullVisitor &vis) override; void accept_vis (HIRExpressionVisitor &vis) override; - std::unique_ptr<Expr> &get_from_expr () { return from; } + Expr &get_from_expr () { return *from; } protected: /* Use covariance to implement clone function as returning this object rather @@ -2542,23 +2029,13 @@ public: // outer attributes not allowed RangeToExpr (Analysis::NodeMapping mappings, std::unique_ptr<Expr> range_to, - location_t locus) - : RangeExpr (std::move (mappings), locus), to (std::move (range_to)) - {} + location_t locus); // Copy constructor with clone - RangeToExpr (RangeToExpr const &other) - : RangeExpr (other), to (other.to->clone_expr ()) - {} + RangeToExpr (RangeToExpr const &other); // Overload assignment operator to clone unique_ptr - RangeToExpr &operator= (RangeToExpr const &other) - { - RangeExpr::operator= (other); - to = other.to->clone_expr (); - - return *this; - } + RangeToExpr &operator= (RangeToExpr const &other); // move constructors RangeToExpr (RangeToExpr &&other) = default; @@ -2567,7 +2044,7 @@ public: void accept_vis (HIRFullVisitor &vis) override; void accept_vis (HIRExpressionVisitor &vis) override; - std::unique_ptr<Expr> &get_to_expr () { return to; } + Expr &get_to_expr () { return *to; } protected: /* Use covariance to implement clone function as returning this object rather @@ -2592,9 +2069,7 @@ class RangeFullExpr : public RangeExpr public: std::string as_string () const override; - RangeFullExpr (Analysis::NodeMapping mappings, location_t locus) - : RangeExpr (std::move (mappings), locus) - {} + RangeFullExpr (Analysis::NodeMapping mappings, location_t locus); // outer attributes not allowed void accept_vis (HIRFullVisitor &vis) override; @@ -2628,27 +2103,14 @@ public: RangeFromToInclExpr (Analysis::NodeMapping mappings, std::unique_ptr<Expr> range_from, - std::unique_ptr<Expr> range_to, location_t locus) - : RangeExpr (std::move (mappings), locus), from (std::move (range_from)), - to (std::move (range_to)) - {} + std::unique_ptr<Expr> range_to, location_t locus); // outer attributes not allowed // Copy constructor with clone - RangeFromToInclExpr (RangeFromToInclExpr const &other) - : RangeExpr (other), from (other.from->clone_expr ()), - to (other.to->clone_expr ()) - {} + RangeFromToInclExpr (RangeFromToInclExpr const &other); // Overload assignment operator to use clone - RangeFromToInclExpr &operator= (RangeFromToInclExpr const &other) - { - RangeExpr::operator= (other); - from = other.from->clone_expr (); - to = other.to->clone_expr (); - - return *this; - } + RangeFromToInclExpr &operator= (RangeFromToInclExpr const &other); // move constructors RangeFromToInclExpr (RangeFromToInclExpr &&other) = default; @@ -2657,8 +2119,8 @@ public: void accept_vis (HIRFullVisitor &vis) override; void accept_vis (HIRExpressionVisitor &vis) override; - std::unique_ptr<Expr> &get_from_expr () { return from; } - std::unique_ptr<Expr> &get_to_expr () { return to; } + Expr &get_from_expr () { return *from; } + Expr &get_to_expr () { return *to; } protected: /* Use covariance to implement clone function as returning this object rather @@ -2686,24 +2148,14 @@ public: std::string as_string () const override; RangeToInclExpr (Analysis::NodeMapping mappings, - std::unique_ptr<Expr> range_to, location_t locus) - : RangeExpr (std::move (mappings), locus), to (std::move (range_to)) - {} + std::unique_ptr<Expr> range_to, location_t locus); // outer attributes not allowed // Copy constructor with clone - RangeToInclExpr (RangeToInclExpr const &other) - : RangeExpr (other), to (other.to->clone_expr ()) - {} + RangeToInclExpr (RangeToInclExpr const &other); // Overload assignment operator to clone pointer - RangeToInclExpr &operator= (RangeToInclExpr const &other) - { - RangeExpr::operator= (other); - to = other.to->clone_expr (); - - return *this; - } + RangeToInclExpr &operator= (RangeToInclExpr const &other); // move constructors RangeToInclExpr (RangeToInclExpr &&other) = default; @@ -2712,7 +2164,7 @@ public: void accept_vis (HIRFullVisitor &vis) override; void accept_vis (HIRExpressionVisitor &vis) override; - std::unique_ptr<Expr> &get_to_expr () { return to; }; + Expr &get_to_expr () { return *to; }; protected: /* Use covariance to implement clone function as returning this object rather @@ -2747,30 +2199,13 @@ public: // Constructor for ReturnExpr. ReturnExpr (Analysis::NodeMapping mappings, location_t locus, std::unique_ptr<Expr> returned_expr = nullptr, - AST::AttrVec outer_attribs = AST::AttrVec ()) - : ExprWithoutBlock (std::move (mappings), std::move (outer_attribs)), - return_expr (std::move (returned_expr)), locus (locus) - {} + AST::AttrVec outer_attribs = AST::AttrVec ()); // Copy constructor with clone - ReturnExpr (ReturnExpr const &other) - : ExprWithoutBlock (other), locus (other.locus) - { - // guard to protect from null pointer dereference - if (other.return_expr != nullptr) - return_expr = other.return_expr->clone_expr (); - } + ReturnExpr (ReturnExpr const &other); // Overloaded assignment operator to clone return_expr pointer - ReturnExpr &operator= (ReturnExpr const &other) - { - ExprWithoutBlock::operator= (other); - return_expr = other.return_expr->clone_expr (); - locus = other.locus; - // outer_attrs = other.outer_attrs; - - return *this; - } + ReturnExpr &operator= (ReturnExpr const &other); // move constructors ReturnExpr (ReturnExpr &&other) = default; @@ -2781,7 +2216,8 @@ public: void accept_vis (HIRFullVisitor &vis) override; void accept_vis (HIRExpressionVisitor &vis) override; - std::unique_ptr<Expr> &get_expr () { return return_expr; } + bool has_expr () { return return_expr != nullptr; } + Expr &get_expr () { return *return_expr; } ExprType get_expression_type () const override final { @@ -2816,27 +2252,13 @@ public: UnsafeBlockExpr (Analysis::NodeMapping mappings, std::unique_ptr<BlockExpr> block_expr, - AST::AttrVec outer_attribs, location_t locus) - : ExprWithBlock (std::move (mappings), std::move (outer_attribs)), - expr (std::move (block_expr)), locus (locus) - {} + AST::AttrVec outer_attribs, location_t locus); // Copy constructor with clone - UnsafeBlockExpr (UnsafeBlockExpr const &other) - : ExprWithBlock (other), expr (other.expr->clone_block_expr ()), - locus (other.locus) - {} + UnsafeBlockExpr (UnsafeBlockExpr const &other); // Overloaded assignment operator to clone - UnsafeBlockExpr &operator= (UnsafeBlockExpr const &other) - { - ExprWithBlock::operator= (other); - expr = other.expr->clone_block_expr (); - locus = other.locus; - // outer_attrs = other.outer_attrs; - - return *this; - } + UnsafeBlockExpr &operator= (UnsafeBlockExpr const &other); // move constructors UnsafeBlockExpr (UnsafeBlockExpr &&other) = default; @@ -2847,7 +2269,7 @@ public: void accept_vis (HIRFullVisitor &vis) override; void accept_vis (HIRExpressionVisitor &vis) override; - std::unique_ptr<BlockExpr> &get_block_expr () { return expr; } + BlockExpr &get_block_expr () { return *expr; } ExprType get_expression_type () const override final { @@ -2874,7 +2296,7 @@ protected: class BaseLoopExpr : public ExprWithBlock { protected: - LoopLabel loop_label; + tl::optional<LoopLabel> loop_label; std::unique_ptr<BlockExpr> loop_block; private: @@ -2884,30 +2306,14 @@ protected: // Constructor for BaseLoopExpr BaseLoopExpr (Analysis::NodeMapping mappings, std::unique_ptr<BlockExpr> loop_block, location_t locus, - LoopLabel loop_label, - AST::AttrVec outer_attribs = AST::AttrVec ()) - : ExprWithBlock (std::move (mappings), std::move (outer_attribs)), - loop_label (std::move (loop_label)), loop_block (std::move (loop_block)), - locus (locus) - {} + tl::optional<LoopLabel> loop_label, + AST::AttrVec outer_attribs = AST::AttrVec ()); // Copy constructor for BaseLoopExpr with clone - BaseLoopExpr (BaseLoopExpr const &other) - : ExprWithBlock (other), loop_label (other.loop_label), - loop_block (other.loop_block->clone_block_expr ()), locus (other.locus) - {} + BaseLoopExpr (BaseLoopExpr const &other); // Overloaded assignment operator to clone - BaseLoopExpr &operator= (BaseLoopExpr const &other) - { - ExprWithBlock::operator= (other); - loop_block = other.loop_block->clone_block_expr (); - loop_label = other.loop_label; - locus = other.locus; - // outer_attrs = other.outer_attrs; - - return *this; - } + BaseLoopExpr &operator= (BaseLoopExpr const &other); // move constructors BaseLoopExpr (BaseLoopExpr &&other) = default; @@ -2919,13 +2325,14 @@ protected: } public: - bool has_loop_label () const { return !loop_label.is_error (); } + bool has_loop_label () const { return loop_label.has_value (); } location_t get_locus () const override final { return locus; } - std::unique_ptr<HIR::BlockExpr> &get_loop_block () { return loop_block; }; + HIR::BlockExpr &get_loop_block () { return *loop_block; }; - LoopLabel &get_loop_label () { return loop_label; } + LoopLabel &get_loop_label () { return loop_label.value (); } + const LoopLabel &get_loop_label () const { return loop_label.value (); } }; // 'Loop' expression (i.e. the infinite loop) HIR node @@ -2937,10 +2344,8 @@ public: // Constructor for LoopExpr LoopExpr (Analysis::NodeMapping mappings, std::unique_ptr<BlockExpr> loop_block, location_t locus, - LoopLabel loop_label, AST::AttrVec outer_attribs = AST::AttrVec ()) - : BaseLoopExpr (std::move (mappings), std::move (loop_block), locus, - std::move (loop_label), std::move (outer_attribs)) - {} + tl::optional<LoopLabel> loop_label, + AST::AttrVec outer_attribs = AST::AttrVec ()); void accept_vis (HIRFullVisitor &vis) override; void accept_vis (HIRExpressionVisitor &vis) override; @@ -2970,29 +2375,14 @@ public: WhileLoopExpr (Analysis::NodeMapping mappings, std::unique_ptr<Expr> loop_condition, std::unique_ptr<BlockExpr> loop_block, location_t locus, - LoopLabel loop_label, - AST::AttrVec outer_attribs = AST::AttrVec ()) - : BaseLoopExpr (std::move (mappings), std::move (loop_block), locus, - std::move (loop_label), std::move (outer_attribs)), - condition (std::move (loop_condition)) - {} + tl::optional<LoopLabel> loop_label, + AST::AttrVec outer_attribs = AST::AttrVec ()); // Copy constructor with clone - WhileLoopExpr (WhileLoopExpr const &other) - : BaseLoopExpr (other), condition (other.condition->clone_expr ()) - {} + WhileLoopExpr (WhileLoopExpr const &other); // Overloaded assignment operator to clone - WhileLoopExpr &operator= (WhileLoopExpr const &other) - { - BaseLoopExpr::operator= (other); - condition = other.condition->clone_expr (); - // loop_block = other.loop_block->clone_block_expr(); - // loop_label = other.loop_label; - // outer_attrs = other.outer_attrs; - - return *this; - } + WhileLoopExpr &operator= (WhileLoopExpr const &other); // move constructors WhileLoopExpr (WhileLoopExpr &&other) = default; @@ -3001,7 +2391,7 @@ public: void accept_vis (HIRFullVisitor &vis) override; void accept_vis (HIRExpressionVisitor &vis) override; - std::unique_ptr<Expr> &get_predicate_expr () { return condition; } + Expr &get_predicate_expr () { return *condition; } protected: /* Use covariance to implement clone function as returning this object rather @@ -3023,7 +2413,7 @@ protected: class WhileLetLoopExpr : public BaseLoopExpr { // MatchArmPatterns patterns; - std::vector<std::unique_ptr<Pattern> > match_arm_patterns; // inlined + std::vector<std::unique_ptr<Pattern>> match_arm_patterns; // inlined std::unique_ptr<Expr> condition; public: @@ -3031,44 +2421,17 @@ public: // Constructor with a loop label WhileLetLoopExpr (Analysis::NodeMapping mappings, - std::vector<std::unique_ptr<Pattern> > match_arm_patterns, + std::vector<std::unique_ptr<Pattern>> match_arm_patterns, std::unique_ptr<Expr> condition, std::unique_ptr<BlockExpr> loop_block, location_t locus, - LoopLabel loop_label, - AST::AttrVec outer_attribs = AST::AttrVec ()) - : BaseLoopExpr (std::move (mappings), std::move (loop_block), locus, - std::move (loop_label), std::move (outer_attribs)), - match_arm_patterns (std::move (match_arm_patterns)), - condition (std::move (condition)) - {} + tl::optional<LoopLabel> loop_label, + AST::AttrVec outer_attribs = AST::AttrVec ()); // Copy constructor with clone - WhileLetLoopExpr (WhileLetLoopExpr const &other) - : BaseLoopExpr (other), - /*match_arm_patterns(other.match_arm_patterns),*/ condition ( - other.condition->clone_expr ()) - { - match_arm_patterns.reserve (other.match_arm_patterns.size ()); - for (const auto &e : other.match_arm_patterns) - match_arm_patterns.push_back (e->clone_pattern ()); - } + WhileLetLoopExpr (WhileLetLoopExpr const &other); // Overloaded assignment operator to clone pointers - WhileLetLoopExpr &operator= (WhileLetLoopExpr const &other) - { - BaseLoopExpr::operator= (other); - // match_arm_patterns = other.match_arm_patterns; - condition = other.condition->clone_expr (); - // loop_block = other.loop_block->clone_block_expr(); - // loop_label = other.loop_label; - // outer_attrs = other.outer_attrs; - - match_arm_patterns.reserve (other.match_arm_patterns.size ()); - for (const auto &e : other.match_arm_patterns) - match_arm_patterns.push_back (e->clone_pattern ()); - - return *this; - } + WhileLetLoopExpr &operator= (WhileLetLoopExpr const &other); // move constructors WhileLetLoopExpr (WhileLetLoopExpr &&other) = default; @@ -3077,8 +2440,8 @@ public: void accept_vis (HIRFullVisitor &vis) override; void accept_vis (HIRExpressionVisitor &vis) override; - std::unique_ptr<Expr> &get_cond () { return condition; } - std::vector<std::unique_ptr<Pattern> > &get_patterns () + Expr &get_cond () { return *condition; } + std::vector<std::unique_ptr<Pattern>> &get_patterns () { return match_arm_patterns; } @@ -3099,9 +2462,6 @@ protected: } }; -// forward decl for IfExpr -class IfLetExpr; - // Base if expression with no "else" or "if let" HIR node class IfExpr : public ExprWithBlock { @@ -3114,29 +2474,14 @@ public: std::string as_string () const override; IfExpr (Analysis::NodeMapping mappings, std::unique_ptr<Expr> condition, - std::unique_ptr<BlockExpr> if_block, location_t locus) - : ExprWithBlock (std::move (mappings), AST::AttrVec ()), - condition (std::move (condition)), if_block (std::move (if_block)), - locus (locus) - {} + std::unique_ptr<BlockExpr> if_block, location_t locus); // outer attributes are never allowed on IfExprs // Copy constructor with clone - IfExpr (IfExpr const &other) - : ExprWithBlock (other), condition (other.condition->clone_expr ()), - if_block (other.if_block->clone_block_expr ()), locus (other.locus) - {} + IfExpr (IfExpr const &other); // Overloaded assignment operator to clone expressions - IfExpr &operator= (IfExpr const &other) - { - ExprWithBlock::operator= (other); - condition = other.condition->clone_expr (); - if_block = other.if_block->clone_block_expr (); - locus = other.locus; - - return *this; - } + IfExpr &operator= (IfExpr const &other); // move constructors IfExpr (IfExpr &&other) = default; @@ -3160,8 +2505,8 @@ public: void vis_if_condition (HIRFullVisitor &vis) { condition->accept_vis (vis); } void vis_if_block (HIRFullVisitor &vis) { if_block->accept_vis (vis); } - std::unique_ptr<Expr> &get_if_condition () { return condition; } - std::unique_ptr<BlockExpr> &get_if_block () { return if_block; } + Expr &get_if_condition () { return *condition; } + BlockExpr &get_if_block () { return *if_block; } ExprType get_expression_type () const final override { return ExprType::If; } @@ -3192,28 +2537,15 @@ public: IfExprConseqElse (Analysis::NodeMapping mappings, std::unique_ptr<Expr> condition, std::unique_ptr<BlockExpr> if_block, - std::unique_ptr<ExprWithBlock> else_block, location_t locus) - : IfExpr (std::move (mappings), std::move (condition), std::move (if_block), - locus), - else_block (std::move (else_block)) - {} + std::unique_ptr<ExprWithBlock> else_block, + location_t locus); // again, outer attributes not allowed // Copy constructor with clone - IfExprConseqElse (IfExprConseqElse const &other) - : IfExpr (other), else_block (other.else_block->clone_expr_with_block ()) - {} + IfExprConseqElse (IfExprConseqElse const &other); // Overloaded assignment operator with cloning - IfExprConseqElse &operator= (IfExprConseqElse const &other) - { - IfExpr::operator= (other); - // condition = other.condition->clone_expr(); - // if_block = other.if_block->clone_block_expr(); - else_block = other.else_block->clone_expr_with_block (); - - return *this; - } + IfExprConseqElse &operator= (IfExprConseqElse const &other); // move constructors IfExprConseqElse (IfExprConseqElse &&other) = default; @@ -3224,7 +2556,7 @@ public: void vis_else_block (HIRFullVisitor &vis) { else_block->accept_vis (vis); } - std::unique_ptr<ExprWithBlock> &get_else_block () { return else_block; } + ExprWithBlock &get_else_block () { return *else_block; } protected: /* Use covariance to implement clone function as returning this object rather @@ -3249,183 +2581,12 @@ protected: } }; -// Basic "if let" expression HIR node with no else -class IfLetExpr : public ExprWithBlock -{ - // MatchArmPatterns patterns; - std::vector<std::unique_ptr<Pattern> > match_arm_patterns; // inlined - std::unique_ptr<Expr> value; - std::unique_ptr<BlockExpr> if_block; - - location_t locus; - -public: - std::string as_string () const override; - - IfLetExpr (Analysis::NodeMapping mappings, - std::vector<std::unique_ptr<Pattern> > match_arm_patterns, - std::unique_ptr<Expr> value, std::unique_ptr<BlockExpr> if_block, - location_t locus) - : ExprWithBlock (std::move (mappings), AST::AttrVec ()), - match_arm_patterns (std::move (match_arm_patterns)), - value (std::move (value)), if_block (std::move (if_block)), locus (locus) - {} - // outer attributes not allowed on if let exprs either - - // copy constructor with clone - IfLetExpr (IfLetExpr const &other) - : ExprWithBlock (other), - /*match_arm_patterns(other.match_arm_patterns),*/ value ( - other.value->clone_expr ()), - if_block (other.if_block->clone_block_expr ()), locus (other.locus) - { - match_arm_patterns.reserve (other.match_arm_patterns.size ()); - for (const auto &e : other.match_arm_patterns) - match_arm_patterns.push_back (e->clone_pattern ()); - } - - // overload assignment operator to clone - IfLetExpr &operator= (IfLetExpr const &other) - { - ExprWithBlock::operator= (other); - // match_arm_patterns = other.match_arm_patterns; - value = other.value->clone_expr (); - if_block = other.if_block->clone_block_expr (); - locus = other.locus; - - match_arm_patterns.reserve (other.match_arm_patterns.size ()); - for (const auto &e : other.match_arm_patterns) - match_arm_patterns.push_back (e->clone_pattern ()); - - return *this; - } - - // move constructors - IfLetExpr (IfLetExpr &&other) = default; - IfLetExpr &operator= (IfLetExpr &&other) = default; - - // Unique pointer custom clone function - std::unique_ptr<IfLetExpr> clone_if_let_expr () const - { - return std::unique_ptr<IfLetExpr> (clone_if_let_expr_impl ()); - } - - location_t get_locus () const override final { return locus; } - - void accept_vis (HIRFullVisitor &vis) override; - void accept_vis (HIRExpressionVisitor &vis) override; - - std::unique_ptr<Expr> &get_scrutinee_expr () { return value; } - - std::vector<std::unique_ptr<Pattern> > &get_patterns () - { - return match_arm_patterns; - } - - std::unique_ptr<BlockExpr> &get_if_block () { return if_block; } - - ExprType get_expression_type () const final override - { - return ExprType::IfLet; - } - -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - IfLetExpr *clone_expr_impl () const override { return new IfLetExpr (*this); } - - /* Use covariance to implement clone function as returning this object rather - * than base */ - IfLetExpr *clone_expr_with_block_impl () const override - { - return new IfLetExpr (*this); - } - - // Base clone function but still concrete as concrete base class - virtual IfLetExpr *clone_if_let_expr_impl () const - { - return new IfLetExpr (*this); - } -}; - -/* HIR node representing "if let" expression with an "else" expression at the - * end */ -class IfLetExprConseqElse : public IfLetExpr -{ - std::unique_ptr<ExprWithBlock> else_block; - -public: - std::string as_string () const override; - - IfLetExprConseqElse ( - Analysis::NodeMapping mappings, - std::vector<std::unique_ptr<Pattern> > match_arm_patterns, - std::unique_ptr<Expr> value, std::unique_ptr<BlockExpr> if_block, - std::unique_ptr<ExprWithBlock> else_block, location_t locus) - : IfLetExpr (std::move (mappings), std::move (match_arm_patterns), - std::move (value), std::move (if_block), locus), - else_block (std::move (else_block)) - {} - // outer attributes not allowed - - // copy constructor with clone - IfLetExprConseqElse (IfLetExprConseqElse const &other) - : IfLetExpr (other), else_block (other.else_block->clone_expr_with_block ()) - {} - - // overload assignment operator to clone - IfLetExprConseqElse &operator= (IfLetExprConseqElse const &other) - { - IfLetExpr::operator= (other); - // match_arm_patterns = other.match_arm_patterns; - // value = other.value->clone_expr(); - // if_block = other.if_block->clone_block_expr(); - else_block = other.else_block->clone_expr_with_block (); - // outer_attrs = other.outer_attrs; - - return *this; - } - - // move constructors - IfLetExprConseqElse (IfLetExprConseqElse &&other) = default; - IfLetExprConseqElse &operator= (IfLetExprConseqElse &&other) = default; - - void accept_vis (HIRFullVisitor &vis) override; - void accept_vis (HIRExpressionVisitor &vis) override; - - void vis_else_block (HIRFullVisitor &vis) { else_block->accept_vis (vis); } - - std::unique_ptr<ExprWithBlock> &get_else_block () { return else_block; } - -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - IfLetExprConseqElse *clone_expr_impl () const override - { - return new IfLetExprConseqElse (*this); - } - - /* Use covariance to implement clone function as returning this object rather - * than base */ - IfLetExprConseqElse *clone_expr_with_block_impl () const override - { - return new IfLetExprConseqElse (*this); - } - - /* Use covariance to implement clone function as returning this object rather - * than base */ - IfLetExprConseqElse *clone_if_let_expr_impl () const override - { - return new IfLetExprConseqElse (*this); - } -}; - // Match arm expression struct MatchArm { private: AST::AttrVec outer_attrs; - std::vector<std::unique_ptr<Pattern> > match_arm_patterns; + std::vector<std::unique_ptr<Pattern>> match_arm_patterns; std::unique_ptr<Expr> guard_expr; location_t locus; @@ -3434,45 +2595,17 @@ public: bool has_match_arm_guard () const { return guard_expr != nullptr; } // Constructor for match arm with a guard expression - MatchArm (std::vector<std::unique_ptr<Pattern> > match_arm_patterns, + MatchArm (std::vector<std::unique_ptr<Pattern>> match_arm_patterns, location_t locus, std::unique_ptr<Expr> guard_expr = nullptr, - AST::AttrVec outer_attrs = AST::AttrVec ()) - : outer_attrs (std::move (outer_attrs)), - match_arm_patterns (std::move (match_arm_patterns)), - guard_expr (std::move (guard_expr)), locus (locus) - {} + AST::AttrVec outer_attrs = AST::AttrVec ()); // Copy constructor with clone - MatchArm (MatchArm const &other) : outer_attrs (other.outer_attrs) - { - // guard to protect from null pointer dereference - if (other.guard_expr != nullptr) - guard_expr = other.guard_expr->clone_expr (); - - match_arm_patterns.reserve (other.match_arm_patterns.size ()); - for (const auto &e : other.match_arm_patterns) - match_arm_patterns.push_back (e->clone_pattern ()); - - locus = other.locus; - } + MatchArm (MatchArm const &other); ~MatchArm () = default; // Overload assignment operator to clone - MatchArm &operator= (MatchArm const &other) - { - outer_attrs = other.outer_attrs; - - if (other.guard_expr != nullptr) - guard_expr = other.guard_expr->clone_expr (); - - match_arm_patterns.clear (); - match_arm_patterns.reserve (other.match_arm_patterns.size ()); - for (const auto &e : other.match_arm_patterns) - match_arm_patterns.push_back (e->clone_pattern ()); - - return *this; - } + MatchArm &operator= (MatchArm const &other); // move constructors MatchArm (MatchArm &&other) = default; @@ -3485,17 +2618,17 @@ public: static MatchArm create_error () { location_t locus = UNDEF_LOCATION; - return MatchArm (std::vector<std::unique_ptr<Pattern> > (), locus); + return MatchArm (std::vector<std::unique_ptr<Pattern>> (), locus); } std::string as_string () const; - std::vector<std::unique_ptr<Pattern> > &get_patterns () + std::vector<std::unique_ptr<Pattern>> &get_patterns () { return match_arm_patterns; } - std::unique_ptr<Expr> &get_guard_expr () { return guard_expr; } + Expr &get_guard_expr () { return *guard_expr; } location_t get_locus () const { return locus; } }; @@ -3511,23 +2644,11 @@ private: public: MatchCase (Analysis::NodeMapping mappings, MatchArm arm, - std::unique_ptr<Expr> expr) - : mappings (mappings), arm (std::move (arm)), expr (std::move (expr)) - {} - - MatchCase (const MatchCase &other) - : mappings (other.mappings), arm (other.arm), - expr (other.expr->clone_expr ()) - {} + std::unique_ptr<Expr> expr); - MatchCase &operator= (const MatchCase &other) - { - mappings = other.mappings; - arm = other.arm; - expr = other.expr->clone_expr (); + MatchCase (const MatchCase &other); - return *this; - } + MatchCase &operator= (const MatchCase &other); MatchCase (MatchCase &&other) = default; MatchCase &operator= (MatchCase &&other) = default; @@ -3539,7 +2660,7 @@ public: Analysis::NodeMapping get_mappings () const { return mappings; } MatchArm &get_arm () { return arm; } - std::unique_ptr<Expr> &get_expr () { return expr; } + Expr &get_expr () { return *expr; } }; // Match expression HIR node @@ -3556,40 +2677,13 @@ public: MatchExpr (Analysis::NodeMapping mappings, std::unique_ptr<Expr> branch_value, std::vector<MatchCase> match_arms, AST::AttrVec inner_attrs, - AST::AttrVec outer_attrs, location_t locus) - : ExprWithBlock (std::move (mappings), std::move (outer_attrs)), - WithInnerAttrs (std::move (inner_attrs)), - branch_value (std::move (branch_value)), - match_arms (std::move (match_arms)), locus (locus) - {} + AST::AttrVec outer_attrs, location_t locus); // Copy constructor requires clone due to unique_ptr - MatchExpr (MatchExpr const &other) - : ExprWithBlock (other), WithInnerAttrs (other.inner_attrs), - branch_value (other.branch_value->clone_expr ()), - match_arms (other.match_arms), locus (other.locus) - { - /*match_arms.reserve (other.match_arms.size ()); - for (const auto &e : other.match_arms) - match_arms.push_back (e->clone_match_case ());*/ - } + MatchExpr (MatchExpr const &other); // Overloaded assignment operator to clone due to unique_ptr - MatchExpr &operator= (MatchExpr const &other) - { - ExprWithBlock::operator= (other); - branch_value = other.branch_value->clone_expr (); - inner_attrs = other.inner_attrs; - match_arms = other.match_arms; - // outer_attrs = other.outer_attrs; - locus = other.locus; - - /*match_arms.reserve (other.match_arms.size ()); - for (const auto &e : other.match_arms) - match_arms.push_back (e->clone_match_case ());*/ - - return *this; - } + MatchExpr &operator= (MatchExpr const &other); // move constructors MatchExpr (MatchExpr &&other) = default; @@ -3600,7 +2694,7 @@ public: void accept_vis (HIRFullVisitor &vis) override; void accept_vis (HIRExpressionVisitor &vis) override; - std::unique_ptr<Expr> &get_scrutinee_expr () { return branch_value; } + Expr &get_scrutinee_expr () { return *branch_value; } AST::AttrVec get_inner_attrs () const { return inner_attrs; } const std::vector<MatchCase> &get_match_cases () const { return match_arms; } std::vector<MatchCase> &get_match_cases () { return match_arms; } @@ -3632,26 +2726,13 @@ class AwaitExpr : public ExprWithoutBlock public: // TODO: ensure outer attributes are actually allowed AwaitExpr (Analysis::NodeMapping mappings, std::unique_ptr<Expr> awaited_expr, - AST::AttrVec outer_attrs, location_t locus) - : ExprWithoutBlock (std::move (mappings), std::move (outer_attrs)), - awaited_expr (std::move (awaited_expr)), locus (locus) - {} + AST::AttrVec outer_attrs, location_t locus); // copy constructor with clone - AwaitExpr (AwaitExpr const &other) - : ExprWithoutBlock (other), - awaited_expr (other.awaited_expr->clone_expr ()), locus (other.locus) - {} + AwaitExpr (AwaitExpr const &other); // overloaded assignment operator with clone - AwaitExpr &operator= (AwaitExpr const &other) - { - ExprWithoutBlock::operator= (other); - awaited_expr = other.awaited_expr->clone_expr (); - locus = other.locus; - - return *this; - } + AwaitExpr &operator= (AwaitExpr const &other); // move constructors AwaitExpr (AwaitExpr &&other) = default; @@ -3664,7 +2745,7 @@ public: void accept_vis (HIRFullVisitor &vis) override; void accept_vis (HIRExpressionVisitor &vis) override; - std::unique_ptr<Expr> &get_awaited_expr () { return awaited_expr; } + Expr &get_awaited_expr () { return *awaited_expr; } ExprType get_expression_type () const final override { @@ -3690,27 +2771,13 @@ class AsyncBlockExpr : public ExprWithBlock public: AsyncBlockExpr (Analysis::NodeMapping mappings, std::unique_ptr<BlockExpr> block_expr, bool has_move, - AST::AttrVec outer_attrs, location_t locus) - : ExprWithBlock (std::move (mappings), std::move (outer_attrs)), - has_move (has_move), block_expr (std::move (block_expr)), locus (locus) - {} + AST::AttrVec outer_attrs, location_t locus); // copy constructor with clone - AsyncBlockExpr (AsyncBlockExpr const &other) - : ExprWithBlock (other), has_move (other.has_move), - block_expr (other.block_expr->clone_block_expr ()), locus (other.locus) - {} + AsyncBlockExpr (AsyncBlockExpr const &other); // overloaded assignment operator to clone - AsyncBlockExpr &operator= (AsyncBlockExpr const &other) - { - ExprWithBlock::operator= (other); - has_move = other.has_move; - block_expr = other.block_expr->clone_block_expr (); - locus = other.locus; - - return *this; - } + AsyncBlockExpr &operator= (AsyncBlockExpr const &other); // move constructors AsyncBlockExpr (AsyncBlockExpr &&other) = default; @@ -3721,7 +2788,7 @@ public: location_t get_locus () const override final { return locus; } bool get_has_move () const { return has_move; } - std::unique_ptr<BlockExpr> &get_block_expr () { return block_expr; } + BlockExpr &get_block_expr () { return *block_expr; } void accept_vis (HIRFullVisitor &vis) override; void accept_vis (HIRExpressionVisitor &vis) override; @@ -3744,35 +2811,17 @@ protected: class OperatorExprMeta { public: - OperatorExprMeta (HIR::CompoundAssignmentExpr &expr) - : node_mappings (expr.get_mappings ()), - lvalue_mappings (expr.get_expr ()->get_mappings ()), - locus (expr.get_locus ()) - {} + OperatorExprMeta (HIR::CompoundAssignmentExpr &expr); - OperatorExprMeta (HIR::ArithmeticOrLogicalExpr &expr) - : node_mappings (expr.get_mappings ()), - lvalue_mappings (expr.get_expr ()->get_mappings ()), - locus (expr.get_locus ()) - {} + OperatorExprMeta (HIR::ArithmeticOrLogicalExpr &expr); - OperatorExprMeta (HIR::NegationExpr &expr) - : node_mappings (expr.get_mappings ()), - lvalue_mappings (expr.get_expr ()->get_mappings ()), - locus (expr.get_locus ()) - {} + OperatorExprMeta (HIR::NegationExpr &expr); - OperatorExprMeta (HIR::DereferenceExpr &expr) - : node_mappings (expr.get_mappings ()), - lvalue_mappings (expr.get_expr ()->get_mappings ()), - locus (expr.get_locus ()) - {} + OperatorExprMeta (HIR::DereferenceExpr &expr); - OperatorExprMeta (HIR::ArrayIndexExpr &expr) - : node_mappings (expr.get_mappings ()), - lvalue_mappings (expr.get_array_expr ()->get_mappings ()), - locus (expr.get_locus ()) - {} + OperatorExprMeta (HIR::ArrayIndexExpr &expr); + + OperatorExprMeta (HIR::ComparisonExpr &expr); const Analysis::NodeMapping &get_mappings () const { return node_mappings; } @@ -3843,26 +2892,158 @@ class InlineAsmRegClass std::string placeholder; }; -struct InlineAsmRegOrRegClass +struct AnonConst { - enum Type + NodeId id; + std::unique_ptr<Expr> expr; + + AnonConst (NodeId id, std::unique_ptr<Expr> expr); + + AnonConst (const AnonConst &other); + + AnonConst operator= (const AnonConst &other); +}; + +class InlineAsmOperand +{ +public: + struct In { - Reg, // links to struct Register - RegClass, // links to struct RegisterClass + tl::optional<struct AST::InlineAsmRegOrRegClass> reg; + std::unique_ptr<Expr> expr; + + In (const tl::optional<struct AST::InlineAsmRegOrRegClass> ®, + std::unique_ptr<Expr> expr); + + In (const struct In &other); + + In operator= (const struct In &other); }; - struct Register + struct Out { - InlineAsmReg Reg; + tl::optional<struct AST::InlineAsmRegOrRegClass> reg; + bool late; + std::unique_ptr<Expr> expr; // can be null + + Out (tl::optional<struct AST::InlineAsmRegOrRegClass> ®, bool late, + std::unique_ptr<Expr> expr); + + Out (const struct Out &other); + + Out operator= (const struct Out &other); }; - struct RegisterClass + struct InOut { - InlineAsmRegClass RegClass; + tl::optional<struct AST::InlineAsmRegOrRegClass> reg; + bool late; + std::unique_ptr<Expr> expr; // this can't be null + + InOut (tl::optional<struct AST::InlineAsmRegOrRegClass> ®, bool late, + std::unique_ptr<Expr> expr); + + InOut (const struct InOut &other); + + InOut operator= (const struct InOut &other); }; - Identifier name; - location_t locus; + struct SplitInOut + { + tl::optional<struct AST::InlineAsmRegOrRegClass> reg; + bool late; + std::unique_ptr<Expr> in_expr; + std::unique_ptr<Expr> out_expr; // could be null + + SplitInOut (tl::optional<struct AST::InlineAsmRegOrRegClass> ®, + bool late, std::unique_ptr<Expr> in_expr, + std::unique_ptr<Expr> out_expr); + + SplitInOut (const struct SplitInOut &other); + + SplitInOut operator= (const struct SplitInOut &other); + }; + + struct Const + { + AnonConst anon_const; + }; + + struct Sym + { + std::unique_ptr<Expr> expr; + + Sym (std::unique_ptr<Expr> expr); + + Sym (const struct Sym &other); + + Sym operator= (const struct Sym &other); + }; + + struct Label + { + std::string label_name; + std::unique_ptr<Expr> expr; + + Label (tl::optional<std::string> label_name, std::unique_ptr<Expr> expr); + + Label (const struct Label &other); + + Label operator= (const struct Label &other); + }; + +private: + using RegisterType = AST::InlineAsmOperand::RegisterType; + AST::InlineAsmOperand::RegisterType register_type; + + tl::optional<struct In> in; + tl::optional<struct Out> out; + tl::optional<struct InOut> in_out; + tl::optional<struct SplitInOut> split_in_out; + tl::optional<struct Const> cnst; + tl::optional<struct Sym> sym; + tl::optional<struct Label> label; + +public: + InlineAsmOperand (const InlineAsmOperand &other) + : register_type (other.register_type), in (other.in), out (other.out), + in_out (other.in_out), split_in_out (other.split_in_out), + cnst (other.cnst), sym (other.sym) + {} + + InlineAsmOperand (const struct In ®) + : register_type (RegisterType::In), in (reg) + {} + + InlineAsmOperand (const struct Out ®) + : register_type (RegisterType::Out), out (reg) + {} + InlineAsmOperand (const struct InOut ®) + : register_type (RegisterType::InOut), in_out (reg) + {} + InlineAsmOperand (const struct SplitInOut ®) + : register_type (RegisterType::SplitInOut), split_in_out (reg) + {} + InlineAsmOperand (const struct Const ®) + : register_type (RegisterType::Const), cnst (reg) + {} + InlineAsmOperand (const struct Sym ®) + : register_type (RegisterType::Sym), sym (reg) + {} + InlineAsmOperand (const struct Label ®) + : register_type (RegisterType::Label), label (reg) + {} + + RegisterType get_register_type () const { return register_type; } + + // Potentially unsafe without get_register_type() check + struct In get_in () const { return in.value (); } + struct Out get_out () const { return out.value (); } + struct InOut get_in_out () const { return in_out.value (); } + struct SplitInOut get_split_in_out () const { return split_in_out.value (); } + struct Const get_const () const { return cnst.value (); } + struct Sym get_sym () const { return sym.value (); } + struct Label get_label () const { return label.value (); } }; // Inline Assembly Node @@ -3876,7 +3057,7 @@ public: std::vector<AST::InlineAsmTemplatePiece> template_; std::vector<AST::TupleTemplateStr> template_strs; - std::vector<AST::InlineAsmOperand> operands; + std::vector<HIR::InlineAsmOperand> operands; std::vector<AST::TupleClobber> clobber_abi; std::set<AST::InlineAsmOption> options; @@ -3909,29 +3090,108 @@ public: return template_strs; } - std::vector<AST::InlineAsmOperand> get_operands () { return operands; } + std::vector<HIR::InlineAsmOperand> get_operands () { return operands; } std::vector<AST::TupleClobber> get_clobber_abi () { return clobber_abi; } std::set<AST::InlineAsmOption> get_options () { return options; } + bool is_simple_asm () + { + // INFO: A simple asm is an asm that does not have any operands + return this->operands.size () == 0; + } + + bool is_inline_asm () + { + // INFO: An inline asm is asm!, which is the opposite of a global_asm() + return !this->is_global_asm; + } + InlineAsm (location_t locus, bool is_global_asm, std::vector<AST::InlineAsmTemplatePiece> template_, std::vector<AST::TupleTemplateStr> template_strs, - std::vector<AST::InlineAsmOperand> operands, + std::vector<HIR::InlineAsmOperand> operands, std::vector<AST::TupleClobber> clobber_abi, std::set<AST::InlineAsmOption> options, Analysis::NodeMapping mappings, - AST::AttrVec outer_attribs = AST::AttrVec ()) - : ExprWithoutBlock (std::move (mappings), std::move (outer_attribs)), - locus (locus), is_global_asm (is_global_asm), - template_ (std::move (template_)), - template_strs (std::move (template_strs)), - operands (std::move (operands)), clobber_abi (std::move (clobber_abi)), - options (std::move (options)) + AST::AttrVec outer_attribs = AST::AttrVec ()); +}; + +struct LlvmOperand +{ + std::string constraint; + std::unique_ptr<Expr> expr; + + LlvmOperand (std::string constraint, std::unique_ptr<Expr> &&expr) + : constraint (constraint), expr (std::move (expr)) + {} + LlvmOperand (const LlvmOperand &other) + : constraint (other.constraint), expr (other.expr->clone_expr ()) {} + LlvmOperand &operator= (const LlvmOperand &other) + { + constraint = other.constraint; + expr = other.expr->clone_expr (); + + return *this; + } +}; + +class LlvmInlineAsm : public ExprWithoutBlock +{ +public: + struct Options + { + bool is_volatile; + bool align_stack; + AST::LlvmInlineAsm::Dialect dialect; + }; + + location_t locus; + AST::AttrVec outer_attrs; + std::vector<LlvmOperand> inputs; + std::vector<LlvmOperand> outputs; + std::vector<AST::TupleTemplateStr> templates; + std::vector<AST::TupleClobber> clobbers; + Options options; + + LlvmInlineAsm (location_t locus, std::vector<LlvmOperand> inputs, + std::vector<LlvmOperand> outputs, + std::vector<AST::TupleTemplateStr> templates, + std::vector<AST::TupleClobber> clobbers, Options options, + AST::AttrVec outer_attrs, Analysis::NodeMapping mappings) + : ExprWithoutBlock (mappings, std::move (outer_attrs)), locus (locus), + inputs (std::move (inputs)), outputs (std::move (outputs)), + templates (std::move (templates)), clobbers (std::move (clobbers)), + options (options) + {} + + AST::LlvmInlineAsm::Dialect get_dialect () { return options.dialect; } + + location_t get_locus () const override { return locus; } + + std::vector<AST::Attribute> &get_outer_attrs () { return outer_attrs; } + + void accept_vis (HIRFullVisitor &vis) override; + void accept_vis (HIRExpressionVisitor &vis) override; + + LlvmInlineAsm *clone_expr_without_block_impl () const override + { + return new LlvmInlineAsm (*this); + } + + std::vector<AST::TupleTemplateStr> &get_templates () { return templates; } + + Expr::ExprType get_expression_type () const override + { + return Expr::ExprType::LlvmInlineAsm; + } + + std::vector<AST::TupleClobber> get_clobbers () { return clobbers; } }; + } // namespace HIR } // namespace Rust diff --git a/gcc/rust/hir/tree/rust-hir-full-decls.h b/gcc/rust/hir/tree/rust-hir-full-decls.h index efe7c45..1e313ec 100644 --- a/gcc/rust/hir/tree/rust-hir-full-decls.h +++ b/gcc/rust/hir/tree/rust-hir-full-decls.h @@ -113,8 +113,6 @@ class WhileLoopExpr; class WhileLetLoopExpr; class IfExpr; class IfExprConseqElse; -class IfLetExpr; -class IfLetExprConseqElse; struct MatchArm; // class MatchCase; // class MatchCaseBlockExpr; @@ -125,8 +123,10 @@ class AwaitExpr; class AsyncBlockExpr; class InlineAsmReg; class InlineAsmRegClass; -struct InlineAsmRegOrRegClass; +struct AnonConst; +class InlineAsmOperand; class InlineAsm; +class LlvmInlineAsm; // rust-stmt.h class EmptyStmt; @@ -212,7 +212,6 @@ class TraitBound; class ImplTraitType; class TraitObjectType; class ParenthesisedType; -class ImplTraitTypeOneBound; class TupleType; class NeverType; class RawPointerType; diff --git a/gcc/rust/hir/tree/rust-hir-generic-param.cc b/gcc/rust/hir/tree/rust-hir-generic-param.cc new file mode 100644 index 0000000..e5afa8e --- /dev/null +++ b/gcc/rust/hir/tree/rust-hir-generic-param.cc @@ -0,0 +1,95 @@ +// Copyright (C) 2020-2024 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-hir-generic-param.h" + +namespace Rust { +namespace HIR { + +GenericParam::GenericParam (Analysis::NodeMapping mapping, + enum GenericKind kind) + : mappings (mapping), kind (kind) +{} + +LifetimeParam::LifetimeParam (Analysis::NodeMapping mappings, Lifetime lifetime, + location_t locus, + std::vector<Lifetime> lifetime_bounds, + AST::AttrVec outer_attrs) + : GenericParam (mappings, GenericKind::LIFETIME), + lifetime (std::move (lifetime)), + lifetime_bounds (std::move (lifetime_bounds)), + outer_attrs (std::move (outer_attrs)), locus (locus) +{} + +LifetimeParam::LifetimeParam (LifetimeParam const &other) + : GenericParam (other.mappings, GenericKind::LIFETIME), + lifetime (other.lifetime), lifetime_bounds (other.lifetime_bounds), + outer_attrs (other.outer_attrs), locus (other.locus) +{} + +LifetimeParam & +LifetimeParam::operator= (LifetimeParam const &other) +{ + lifetime = other.lifetime; + lifetime_bounds = other.lifetime_bounds; + outer_attrs = other.outer_attrs; + locus = other.locus; + mappings = other.mappings; + + return *this; +} + +ConstGenericParam::ConstGenericParam (std::string name, + std::unique_ptr<Type> type, + std::unique_ptr<Expr> default_expression, + Analysis::NodeMapping mapping, + location_t locus) + : GenericParam (mapping, GenericKind::CONST), name (std::move (name)), + type (std::move (type)), + default_expression (std::move (default_expression)), locus (locus) +{} + +ConstGenericParam::ConstGenericParam (const ConstGenericParam &other) + : GenericParam (other) +{ + name = other.name; + locus = other.locus; + + if (other.type) + type = other.type->clone_type (); + if (other.default_expression) + default_expression = other.default_expression->clone_expr (); +} + +std::string +ConstGenericParam::as_string () const +{ + auto result = "ConstGenericParam: " + name + " : " + type->as_string (); + + if (default_expression) + result += " = " + default_expression->as_string (); + + return result; +} + +void +ConstGenericParam::accept_vis (HIRFullVisitor &) +{} + +} // namespace HIR +} // namespace Rust diff --git a/gcc/rust/hir/tree/rust-hir-generic-param.h b/gcc/rust/hir/tree/rust-hir-generic-param.h new file mode 100644 index 0000000..960de56 --- /dev/null +++ b/gcc/rust/hir/tree/rust-hir-generic-param.h @@ -0,0 +1,187 @@ + +// Copyright (C) 2020-2024 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_HIR_GENERIC_PARAM_H +#define RUST_HIR_GENERIC_PARAM_H + +#include "rust-hir-visitable.h" +#include "rust-hir-bound.h" + +namespace Rust { +namespace HIR { + +/* Base generic parameter in HIR. Abstract - can be represented by a Lifetime or + * Type param */ +class GenericParam : public FullVisitable +{ +public: + using FullVisitable::accept_vis; + + virtual ~GenericParam () {} + + enum class GenericKind + { + TYPE, + LIFETIME, + CONST, + }; + + virtual AST::AttrVec &get_outer_attrs () = 0; + virtual bool has_outer_attribute () const = 0; + + // Unique pointer custom clone function + std::unique_ptr<GenericParam> clone_generic_param () const + { + return std::unique_ptr<GenericParam> (clone_generic_param_impl ()); + } + + virtual std::string as_string () const = 0; + + virtual location_t get_locus () const = 0; + + Analysis::NodeMapping get_mappings () const { return mappings; } + + enum GenericKind get_kind () const { return kind; } + +protected: + // Clone function implementation as pure virtual method + virtual GenericParam *clone_generic_param_impl () const = 0; + + Analysis::NodeMapping mappings; + + enum GenericKind kind; + + GenericParam (Analysis::NodeMapping mapping, + enum GenericKind kind = GenericKind::TYPE); +}; + +// A lifetime generic parameter (as opposed to a type generic parameter) +class LifetimeParam : public GenericParam +{ + Lifetime lifetime; + + // bool has_lifetime_bounds; + // LifetimeBounds lifetime_bounds; + std::vector<Lifetime> lifetime_bounds; // inlined LifetimeBounds + + AST::AttrVec outer_attrs; + + location_t locus; + +public: + Lifetime get_lifetime () { return lifetime; } + + // Returns whether the lifetime param has any lifetime bounds. + bool has_lifetime_bounds () const { return !lifetime_bounds.empty (); } + + std::vector<Lifetime> &get_lifetime_bounds () { return lifetime_bounds; } + + // Returns whether the lifetime param has an outer attribute. + bool has_outer_attribute () const override { return outer_attrs.size () > 1; } + + AST::AttrVec &get_outer_attrs () override { return outer_attrs; } + + // Constructor + LifetimeParam (Analysis::NodeMapping mappings, Lifetime lifetime, + location_t locus = UNDEF_LOCATION, + std::vector<Lifetime> lifetime_bounds + = std::vector<Lifetime> (), + AST::AttrVec outer_attrs = std::vector<AST::Attribute> ()); + + // TODO: remove copy and assignment operator definitions - not required + + // Copy constructor with clone + LifetimeParam (LifetimeParam const &other); + + // Overloaded assignment operator to clone attribute + LifetimeParam &operator= (LifetimeParam const &other); + + // move constructors + LifetimeParam (LifetimeParam &&other) = default; + LifetimeParam &operator= (LifetimeParam &&other) = default; + + std::string as_string () const override; + + void accept_vis (HIRFullVisitor &vis) override; + + location_t get_locus () const override final { return locus; } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + LifetimeParam *clone_generic_param_impl () const override + { + return new LifetimeParam (*this); + } +}; + +class ConstGenericParam : public GenericParam +{ +public: + ConstGenericParam (std::string name, std::unique_ptr<Type> type, + std::unique_ptr<Expr> default_expression, + Analysis::NodeMapping mapping, location_t locus); + + ConstGenericParam (const ConstGenericParam &other); + + bool has_outer_attribute () const override { return false; } + + AST::AttrVec &get_outer_attrs () override { return outer_attrs; } + + std::string as_string () const override final; + + void accept_vis (HIRFullVisitor &vis) override final; + + location_t get_locus () const override final { return locus; }; + + bool has_default_expression () { return default_expression != nullptr; } + + std::string get_name () { return name; } + Type &get_type () + { + rust_assert (type); + return *type; + } + Expr &get_default_expression () { return *default_expression; } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + ConstGenericParam *clone_generic_param_impl () const override + { + return new ConstGenericParam (*this); + } + +private: + std::string name; + std::unique_ptr<Type> type; + + /* const params have no outer attrs, should be empty */ + AST::AttrVec outer_attrs = std::vector<AST::Attribute> (); + + /* Optional - can be a null pointer if there is no default expression */ + std::unique_ptr<Expr> default_expression; + + location_t locus; +}; + +} // namespace HIR +} // namespace Rust + +#endif diff --git a/gcc/rust/hir/tree/rust-hir-item.cc b/gcc/rust/hir/tree/rust-hir-item.cc new file mode 100644 index 0000000..160f710 --- /dev/null +++ b/gcc/rust/hir/tree/rust-hir-item.cc @@ -0,0 +1,1024 @@ +// Copyright (C) 2020-2024 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-hir-item.h" +#include "optional.h" + +namespace Rust { +namespace HIR { + +TypeParam::TypeParam ( + Analysis::NodeMapping mappings, Identifier type_representation, + location_t locus, + std::vector<std::unique_ptr<TypeParamBound>> type_param_bounds, + tl::optional<std::unique_ptr<Type>> type, AST::AttrVec outer_attrs) + : GenericParam (mappings), outer_attrs (std::move (outer_attrs)), + type_representation (std::move (type_representation)), + type_param_bounds (std::move (type_param_bounds)), type (std::move (type)), + locus (locus) +{} + +TypeParam::TypeParam (TypeParam const &other) + : GenericParam (other.mappings), outer_attrs (other.outer_attrs), + type_representation (other.type_representation), locus (other.locus) +{ + // guard to prevent null pointer dereference + if (other.has_type ()) + type = {other.type.value ()->clone_type ()}; + else + type = tl::nullopt; + + type_param_bounds.reserve (other.type_param_bounds.size ()); + for (const auto &e : other.type_param_bounds) + type_param_bounds.push_back (e->clone_type_param_bound ()); +} + +TypeParam & +TypeParam::operator= (TypeParam const &other) +{ + type_representation = other.type_representation; + outer_attrs = other.outer_attrs; + locus = other.locus; + mappings = other.mappings; + + // guard to prevent null pointer dereference + if (other.has_type ()) + type = {other.type.value ()->clone_type ()}; + else + type = tl::nullopt; + + type_param_bounds.reserve (other.type_param_bounds.size ()); + for (const auto &e : other.type_param_bounds) + type_param_bounds.push_back (e->clone_type_param_bound ()); + + return *this; +} + +Analysis::NodeMapping +TypeParam::get_type_mappings () const +{ + rust_assert (type.has_value ()); + return type.value ()->get_mappings (); +} + +std::vector<std::unique_ptr<TypeParamBound>> & +TypeParam::get_type_param_bounds () +{ + return type_param_bounds; +} + +TypeBoundWhereClauseItem::TypeBoundWhereClauseItem ( + Analysis::NodeMapping mappings, std::vector<LifetimeParam> for_lifetimes, + std::unique_ptr<Type> bound_type, + std::vector<std::unique_ptr<TypeParamBound>> type_param_bounds, + location_t locus) + : for_lifetimes (std::move (for_lifetimes)), + bound_type (std::move (bound_type)), + type_param_bounds (std::move (type_param_bounds)), + mappings (std::move (mappings)), locus (locus) +{} + +TypeBoundWhereClauseItem::TypeBoundWhereClauseItem ( + TypeBoundWhereClauseItem const &other) + : for_lifetimes (other.for_lifetimes), + bound_type (other.bound_type->clone_type ()), mappings (other.mappings) +{ + type_param_bounds.reserve (other.type_param_bounds.size ()); + for (const auto &e : other.type_param_bounds) + type_param_bounds.push_back (e->clone_type_param_bound ()); +} + +TypeBoundWhereClauseItem & +TypeBoundWhereClauseItem::operator= (TypeBoundWhereClauseItem const &other) +{ + mappings = other.mappings; + for_lifetimes = other.for_lifetimes; + bound_type = other.bound_type->clone_type (); + type_param_bounds.reserve (other.type_param_bounds.size ()); + for (const auto &e : other.type_param_bounds) + type_param_bounds.push_back (e->clone_type_param_bound ()); + + return *this; +} + +std::vector<std::unique_ptr<TypeParamBound>> & +TypeBoundWhereClauseItem::get_type_param_bounds () +{ + return type_param_bounds; +} + +SelfParam::SelfParam (Analysis::NodeMapping mappings, + ImplicitSelfKind self_kind, + tl::optional<Lifetime> lifetime, Type *type) + : self_kind (self_kind), lifetime (std::move (lifetime)), type (type), + mappings (mappings) +{} + +SelfParam::SelfParam (Analysis::NodeMapping mappings, + std::unique_ptr<Type> type, bool is_mut, location_t locus) + : self_kind (is_mut ? ImplicitSelfKind::MUT : ImplicitSelfKind::IMM), + lifetime (tl::nullopt), type (std::move (type)), locus (locus), + mappings (mappings) +{} + +SelfParam::SelfParam (Analysis::NodeMapping mappings, + tl::optional<Lifetime> lifetime, bool is_mut, + location_t locus) + : self_kind (is_mut ? ImplicitSelfKind::MUT_REF : ImplicitSelfKind::IMM_REF), + lifetime (std::move (lifetime)), locus (locus), mappings (mappings) +{} + +SelfParam::SelfParam (SelfParam const &other) + : self_kind (other.self_kind), lifetime (other.lifetime), locus (other.locus), + mappings (other.mappings) +{ + if (other.type != nullptr) + type = other.type->clone_type (); +} + +SelfParam & +SelfParam::operator= (SelfParam const &other) +{ + if (other.type != nullptr) + type = other.type->clone_type (); + + self_kind = other.self_kind; + lifetime = other.lifetime; + locus = other.locus; + mappings = other.mappings; + + return *this; +} + +Mutability +SelfParam::get_mut () const +{ + return (self_kind == ImplicitSelfKind::MUT + || self_kind == ImplicitSelfKind::MUT_REF) + ? Mutability::Mut + : Mutability::Imm; +} + +bool +SelfParam::is_mut () const +{ + return self_kind == ImplicitSelfKind::MUT + || self_kind == ImplicitSelfKind::MUT_REF; +} + +bool +SelfParam::is_ref () const +{ + return self_kind == ImplicitSelfKind::IMM_REF + || self_kind == ImplicitSelfKind::MUT_REF; +} + +FunctionParam::FunctionParam (Analysis::NodeMapping mappings, + std::unique_ptr<Pattern> param_name, + std::unique_ptr<Type> param_type, + location_t locus) + : param_name (std::move (param_name)), type (std::move (param_type)), + locus (locus), mappings (mappings) +{} + +FunctionParam::FunctionParam (FunctionParam const &other) + : param_name (other.param_name->clone_pattern ()), + type (other.type->clone_type ()), locus (other.locus), + mappings (other.mappings) +{} + +FunctionParam & +FunctionParam::operator= (FunctionParam const &other) +{ + param_name = other.param_name->clone_pattern (); + type = other.type->clone_type (); + locus = other.locus; + mappings = other.mappings; + + return *this; +} + +VisItem & +VisItem::operator= (VisItem const &other) +{ + Item::operator= (other); + visibility = other.visibility; + // outer_attrs = other.outer_attrs; + + return *this; +} + +VisItem::VisItem (VisItem const &other) + : Item (other), visibility (other.visibility) +{} + +Module::Module (Analysis::NodeMapping mappings, Identifier module_name, + location_t locus, std::vector<std::unique_ptr<Item>> items, + Visibility visibility, AST::AttrVec inner_attrs, + AST::AttrVec outer_attrs) + : VisItem (std::move (mappings), std::move (visibility), + std::move (outer_attrs)), + WithInnerAttrs (std::move (inner_attrs)), module_name (module_name), + locus (locus), items (std::move (items)) +{} + +Module::Module (Module const &other) + : VisItem (other), WithInnerAttrs (other.inner_attrs), module_name ("") +{ + items.reserve (other.items.size ()); + for (const auto &e : other.items) + items.push_back (e->clone_item ()); +} + +Module & +Module::operator= (Module const &other) +{ + VisItem::operator= (other); + inner_attrs = other.inner_attrs; + + items.reserve (other.items.size ()); + for (const auto &e : other.items) + items.push_back (e->clone_item ()); + + return *this; +} + +Function::Function (Analysis::NodeMapping mappings, Identifier function_name, + FunctionQualifiers qualifiers, + std::vector<std::unique_ptr<GenericParam>> generic_params, + std::vector<FunctionParam> function_params, + std::unique_ptr<Type> return_type, WhereClause where_clause, + std::unique_ptr<BlockExpr> function_body, Visibility vis, + AST::AttrVec outer_attrs, tl::optional<SelfParam> self, + Defaultness defaultness, location_t locus) + : VisItem (std::move (mappings), std::move (vis), std::move (outer_attrs)), + qualifiers (std::move (qualifiers)), + function_name (std::move (function_name)), + generic_params (std::move (generic_params)), + function_params (std::move (function_params)), + return_type (std::move (return_type)), + where_clause (std::move (where_clause)), + function_body (std::move (function_body)), self (std::move (self)), + locus (locus), defaultness (defaultness) +{} + +Function::Function (Function const &other) + : VisItem (other), qualifiers (other.qualifiers), + function_name (other.function_name), + function_params (other.function_params), where_clause (other.where_clause), + function_body (other.function_body->clone_block_expr ()), self (other.self), + locus (other.locus), defaultness (other.defaultness) +{ + // guard to prevent null dereference (always required) + if (other.return_type != nullptr) + return_type = other.return_type->clone_type (); + else + return_type = nullptr; + + generic_params.reserve (other.generic_params.size ()); + for (const auto &e : other.generic_params) + generic_params.push_back (e->clone_generic_param ()); +} + +Function & +Function::operator= (Function const &other) +{ + VisItem::operator= (other); + function_name = other.function_name; + qualifiers = other.qualifiers; + function_params = other.function_params; + + // guard to prevent null dereference (always required) + if (other.return_type != nullptr) + return_type = other.return_type->clone_type (); + else + return_type = nullptr; + + where_clause = other.where_clause; + function_body = other.function_body->clone_block_expr (); + locus = other.locus; + self = other.self; + + defaultness = other.defaultness; + + generic_params.reserve (other.generic_params.size ()); + for (const auto &e : other.generic_params) + generic_params.push_back (e->clone_generic_param ()); + + return *this; +} + +TypeAlias::TypeAlias (Analysis::NodeMapping mappings, Identifier new_type_name, + std::vector<std::unique_ptr<GenericParam>> generic_params, + WhereClause where_clause, + std::unique_ptr<Type> existing_type, Visibility vis, + AST::AttrVec outer_attrs, location_t locus) + : VisItem (std::move (mappings), std::move (vis), std::move (outer_attrs)), + new_type_name (std::move (new_type_name)), + generic_params (std::move (generic_params)), + where_clause (std::move (where_clause)), + existing_type (std::move (existing_type)), locus (locus) +{} + +TypeAlias::TypeAlias (TypeAlias const &other) + : VisItem (other), new_type_name (other.new_type_name), + where_clause (other.where_clause), + existing_type (other.existing_type->clone_type ()), locus (other.locus) +{ + generic_params.reserve (other.generic_params.size ()); + for (const auto &e : other.generic_params) + generic_params.push_back (e->clone_generic_param ()); +} + +TypeAlias & +TypeAlias::operator= (TypeAlias const &other) +{ + VisItem::operator= (other); + new_type_name = other.new_type_name; + where_clause = other.where_clause; + existing_type = other.existing_type->clone_type (); + locus = other.locus; + + generic_params.reserve (other.generic_params.size ()); + for (const auto &e : other.generic_params) + generic_params.push_back (e->clone_generic_param ()); + + return *this; +} + +StructField::StructField (Analysis::NodeMapping mappings, Identifier field_name, + std::unique_ptr<Type> field_type, Visibility vis, + location_t locus, AST::AttrVec outer_attrs) + : outer_attrs (std::move (outer_attrs)), visibility (std::move (vis)), + field_name (std::move (field_name)), field_type (std::move (field_type)), + mappings (mappings), locus (locus) +{} + +StructField::StructField (StructField const &other) + : outer_attrs (other.outer_attrs), visibility (other.visibility), + field_name (other.field_name), field_type (other.field_type->clone_type ()), + mappings (other.mappings) +{} + +StructField & +StructField::operator= (StructField const &other) +{ + field_name = other.field_name; + field_type = other.field_type->clone_type (); + visibility = other.visibility; + outer_attrs = other.outer_attrs; + mappings = other.mappings; + + return *this; +} + +TupleField::TupleField (Analysis::NodeMapping mapping, + std::unique_ptr<Type> field_type, Visibility vis, + location_t locus, AST::AttrVec outer_attrs) + : outer_attrs (std::move (outer_attrs)), visibility (std::move (vis)), + field_type (std::move (field_type)), locus (locus), mappings (mapping) +{} + +TupleField::TupleField (TupleField const &other) + : outer_attrs (other.outer_attrs), visibility (other.visibility), + field_type (other.field_type->clone_type ()), locus (other.locus), + mappings (other.mappings) +{} + +TupleField & +TupleField::operator= (TupleField const &other) +{ + field_type = other.field_type->clone_type (); + visibility = other.visibility; + outer_attrs = other.outer_attrs; + locus = other.locus; + mappings = other.mappings; + + return *this; +} + +TupleStruct::TupleStruct ( + Analysis::NodeMapping mappings, std::vector<TupleField> fields, + Identifier struct_name, + std::vector<std::unique_ptr<GenericParam>> generic_params, + WhereClause where_clause, Visibility vis, AST::AttrVec outer_attrs, + location_t locus) + : Struct (std::move (mappings), std::move (struct_name), + std::move (generic_params), std::move (where_clause), + std::move (vis), locus, std::move (outer_attrs)), + fields (std::move (fields)) +{} + +EnumItem::EnumItem (Analysis::NodeMapping mappings, Identifier variant_name, + AST::AttrVec outer_attrs, location_t locus) + : Item (std::move (mappings), std::move (outer_attrs)), + variant_name (std::move (variant_name)), locus (locus) +{} + +EnumItemTuple::EnumItemTuple (Analysis::NodeMapping mappings, + Identifier variant_name, + std::vector<TupleField> tuple_fields, + AST::AttrVec outer_attrs, location_t locus) + : EnumItem (std::move (mappings), std::move (variant_name), + std::move (outer_attrs), locus), + tuple_fields (std::move (tuple_fields)) +{} + +EnumItemStruct::EnumItemStruct (Analysis::NodeMapping mappings, + Identifier variant_name, + std::vector<StructField> struct_fields, + AST::AttrVec outer_attrs, location_t locus) + : EnumItem (std::move (mappings), std::move (variant_name), + std::move (outer_attrs), locus), + struct_fields (std::move (struct_fields)) +{} + +EnumItemDiscriminant::EnumItemDiscriminant (Analysis::NodeMapping mappings, + Identifier variant_name, + std::unique_ptr<Expr> expr, + AST::AttrVec outer_attrs, + location_t locus) + : EnumItem (std::move (mappings), std::move (variant_name), + std::move (outer_attrs), locus), + expression (std::move (expr)) +{} + +EnumItemDiscriminant::EnumItemDiscriminant (EnumItemDiscriminant const &other) + : EnumItem (other), expression (other.expression->clone_expr ()) +{} + +EnumItemDiscriminant & +EnumItemDiscriminant::operator= (EnumItemDiscriminant const &other) +{ + EnumItem::operator= (other); + expression = other.expression->clone_expr (); + // variant_name = other.variant_name; + // outer_attrs = other.outer_attrs; + + return *this; +} + +Enum::Enum (Analysis::NodeMapping mappings, Identifier enum_name, + Visibility vis, + std::vector<std::unique_ptr<GenericParam>> generic_params, + WhereClause where_clause, + std::vector<std::unique_ptr<EnumItem>> items, + AST::AttrVec outer_attrs, location_t locus) + : VisItem (std::move (mappings), std::move (vis), std::move (outer_attrs)), + enum_name (std::move (enum_name)), + generic_params (std::move (generic_params)), + where_clause (std::move (where_clause)), items (std::move (items)), + locus (locus) +{} + +Enum::Enum (Enum const &other) + : VisItem (other), enum_name (other.enum_name), + where_clause (other.where_clause), locus (other.locus) +{ + generic_params.reserve (other.generic_params.size ()); + for (const auto &e : other.generic_params) + generic_params.push_back (e->clone_generic_param ()); + + items.reserve (other.items.size ()); + for (const auto &e : other.items) + items.push_back (e->clone_enum_item ()); +} + +Enum & +Enum::operator= (Enum const &other) +{ + VisItem::operator= (other); + enum_name = other.enum_name; + where_clause = other.where_clause; + locus = other.locus; + + generic_params.reserve (other.generic_params.size ()); + for (const auto &e : other.generic_params) + generic_params.push_back (e->clone_generic_param ()); + + items.reserve (other.items.size ()); + for (const auto &e : other.items) + items.push_back (e->clone_enum_item ()); + + return *this; +} + +Union::Union (Analysis::NodeMapping mappings, Identifier union_name, + Visibility vis, + std::vector<std::unique_ptr<GenericParam>> generic_params, + WhereClause where_clause, std::vector<StructField> variants, + AST::AttrVec outer_attrs, location_t locus) + : VisItem (std::move (mappings), std::move (vis), std::move (outer_attrs)), + union_name (std::move (union_name)), + generic_params (std::move (generic_params)), + where_clause (std::move (where_clause)), variants (std::move (variants)), + locus (locus) +{} + +Union::Union (Union const &other) + : VisItem (other), union_name (other.union_name), + where_clause (other.where_clause), variants (other.variants), + locus (other.locus) +{ + generic_params.reserve (other.generic_params.size ()); + for (const auto &e : other.generic_params) + generic_params.push_back (e->clone_generic_param ()); +} + +Union & +Union::operator= (Union const &other) +{ + VisItem::operator= (other); + union_name = other.union_name; + where_clause = other.where_clause; + variants = other.variants; + locus = other.locus; + + generic_params.reserve (other.generic_params.size ()); + for (const auto &e : other.generic_params) + generic_params.push_back (e->clone_generic_param ()); + + return *this; +} + +ConstantItem::ConstantItem (Analysis::NodeMapping mappings, Identifier ident, + Visibility vis, std::unique_ptr<Type> type, + std::unique_ptr<Expr> const_expr, + AST::AttrVec outer_attrs, location_t locus) + : VisItem (std::move (mappings), std::move (vis), std::move (outer_attrs)), + identifier (std::move (ident)), type (std::move (type)), + const_expr (std::move (const_expr)), locus (locus) +{} + +ConstantItem::ConstantItem (ConstantItem const &other) + : VisItem (other), identifier (other.identifier), + type (other.type->clone_type ()), + const_expr (other.const_expr->clone_expr ()), locus (other.locus) +{} + +ConstantItem & +ConstantItem::operator= (ConstantItem const &other) +{ + VisItem::operator= (other); + identifier = other.identifier; + type = other.type->clone_type (); + const_expr = other.const_expr->clone_expr (); + locus = other.locus; + + return *this; +} + +StaticItem::StaticItem (Analysis::NodeMapping mappings, Identifier name, + Mutability mut, std::unique_ptr<Type> type, + std::unique_ptr<Expr> expr, Visibility vis, + AST::AttrVec outer_attrs, location_t locus) + : VisItem (std::move (mappings), std::move (vis), std::move (outer_attrs)), + mut (mut), name (std::move (name)), type (std::move (type)), + expr (std::move (expr)), locus (locus) +{} + +StaticItem::StaticItem (StaticItem const &other) + : VisItem (other), mut (other.mut), name (other.name), + type (other.type->clone_type ()), expr (other.expr->clone_expr ()), + locus (other.locus) +{} + +StaticItem & +StaticItem::operator= (StaticItem const &other) +{ + VisItem::operator= (other); + name = other.name; + mut = other.mut; + type = other.type->clone_type (); + expr = other.expr->clone_expr (); + locus = other.locus; + + return *this; +} + +TraitFunctionDecl::TraitFunctionDecl ( + Identifier function_name, FunctionQualifiers qualifiers, + std::vector<std::unique_ptr<GenericParam>> generic_params, + tl::optional<SelfParam> self, std::vector<FunctionParam> function_params, + std::unique_ptr<Type> return_type, WhereClause where_clause) + : qualifiers (std::move (qualifiers)), + function_name (std::move (function_name)), + generic_params (std::move (generic_params)), + function_params (std::move (function_params)), + return_type (std::move (return_type)), + where_clause (std::move (where_clause)), self (std::move (self)) +{} + +TraitFunctionDecl::TraitFunctionDecl (TraitFunctionDecl const &other) + : qualifiers (other.qualifiers), function_name (other.function_name), + function_params (other.function_params), + return_type (other.return_type->clone_type ()), + where_clause (other.where_clause), self (other.self) +{ + generic_params.reserve (other.generic_params.size ()); + for (const auto &e : other.generic_params) + generic_params.push_back (e->clone_generic_param ()); +} + +TraitFunctionDecl & +TraitFunctionDecl::operator= (TraitFunctionDecl const &other) +{ + function_name = other.function_name; + qualifiers = other.qualifiers; + function_params = other.function_params; + return_type = other.return_type->clone_type (); + where_clause = other.where_clause; + self = other.self; + + generic_params.reserve (other.generic_params.size ()); + for (const auto &e : other.generic_params) + generic_params.push_back (e->clone_generic_param ()); + + return *this; +} + +TraitItemFunc::TraitItemFunc (Analysis::NodeMapping mappings, + TraitFunctionDecl decl, + std::unique_ptr<BlockExpr> block_expr, + AST::AttrVec outer_attrs, location_t locus) + : TraitItem (mappings), outer_attrs (std::move (outer_attrs)), + decl (std::move (decl)), block_expr (std::move (block_expr)), locus (locus) +{} + +TraitItemFunc::TraitItemFunc (TraitItemFunc const &other) + : TraitItem (other.mappings), outer_attrs (other.outer_attrs), + decl (other.decl), locus (other.locus) +{ + if (other.block_expr != nullptr) + block_expr = other.block_expr->clone_block_expr (); +} + +TraitItemFunc & +TraitItemFunc::operator= (TraitItemFunc const &other) +{ + TraitItem::operator= (other); + outer_attrs = other.outer_attrs; + decl = other.decl; + locus = other.locus; + mappings = other.mappings; + if (other.block_expr != nullptr) + block_expr = other.block_expr->clone_block_expr (); + + return *this; +} + +TraitItemConst::TraitItemConst (Analysis::NodeMapping mappings, Identifier name, + std::unique_ptr<Type> type, + std::unique_ptr<Expr> expr, + AST::AttrVec outer_attrs, location_t locus) + : TraitItem (mappings), outer_attrs (std::move (outer_attrs)), + name (std::move (name)), type (std::move (type)), expr (std::move (expr)), + locus (locus) +{} + +TraitItemConst::TraitItemConst (TraitItemConst const &other) + : TraitItem (other.mappings), outer_attrs (other.outer_attrs), + name (other.name), type (other.type->clone_type ()), + expr (other.expr->clone_expr ()), locus (other.locus) +{} + +TraitItemConst & +TraitItemConst::operator= (TraitItemConst const &other) +{ + TraitItem::operator= (other); + outer_attrs = other.outer_attrs; + name = other.name; + type = other.type->clone_type (); + expr = other.expr->clone_expr (); + locus = other.locus; + mappings = other.mappings; + + return *this; +} + +TraitItemType::TraitItemType ( + Analysis::NodeMapping mappings, Identifier name, + std::vector<std::unique_ptr<TypeParamBound>> type_param_bounds, + AST::AttrVec outer_attrs, location_t locus) + : TraitItem (mappings), outer_attrs (std::move (outer_attrs)), + name (std::move (name)), type_param_bounds (std::move (type_param_bounds)), + locus (locus) +{} + +TraitItemType::TraitItemType (TraitItemType const &other) + : TraitItem (other.mappings), outer_attrs (other.outer_attrs), + name (other.name), locus (other.locus) +{ + type_param_bounds.reserve (other.type_param_bounds.size ()); + for (const auto &e : other.type_param_bounds) + type_param_bounds.push_back (e->clone_type_param_bound ()); +} + +TraitItemType & +TraitItemType::operator= (TraitItemType const &other) +{ + TraitItem::operator= (other); + outer_attrs = other.outer_attrs; + name = other.name; + locus = other.locus; + mappings = other.mappings; + + type_param_bounds.reserve (other.type_param_bounds.size ()); + for (const auto &e : other.type_param_bounds) + type_param_bounds.push_back (e->clone_type_param_bound ()); + + return *this; +} + +Trait::Trait (Analysis::NodeMapping mappings, Identifier name, + Unsafety unsafety, + std::vector<std::unique_ptr<GenericParam>> generic_params, + std::vector<std::unique_ptr<TypeParamBound>> type_param_bounds, + WhereClause where_clause, + std::vector<std::unique_ptr<TraitItem>> trait_items, + Visibility vis, AST::AttrVec outer_attrs, location_t locus) + : VisItem (std::move (mappings), std::move (vis), std::move (outer_attrs)), + unsafety (unsafety), name (std::move (name)), + generic_params (std::move (generic_params)), + type_param_bounds (std::move (type_param_bounds)), + where_clause (std::move (where_clause)), + trait_items (std::move (trait_items)), locus (locus) +{} + +Trait::Trait (Trait const &other) + : VisItem (other), unsafety (other.unsafety), name (other.name), + where_clause (other.where_clause), locus (other.locus) +{ + generic_params.reserve (other.generic_params.size ()); + for (const auto &e : other.generic_params) + generic_params.push_back (e->clone_generic_param ()); + + type_param_bounds.reserve (other.type_param_bounds.size ()); + for (const auto &e : other.type_param_bounds) + type_param_bounds.push_back (e->clone_type_param_bound ()); + + trait_items.reserve (other.trait_items.size ()); + for (const auto &e : other.trait_items) + trait_items.push_back (e->clone_trait_item ()); +} + +Trait & +Trait::operator= (Trait const &other) +{ + VisItem::operator= (other); + name = other.name; + unsafety = other.unsafety; + where_clause = other.where_clause; + locus = other.locus; + + generic_params.reserve (other.generic_params.size ()); + for (const auto &e : other.generic_params) + generic_params.push_back (e->clone_generic_param ()); + + type_param_bounds.reserve (other.type_param_bounds.size ()); + for (const auto &e : other.type_param_bounds) + type_param_bounds.push_back (e->clone_type_param_bound ()); + + trait_items.reserve (other.trait_items.size ()); + for (const auto &e : other.trait_items) + trait_items.push_back (e->clone_trait_item ()); + + return *this; +} + +ImplBlock::ImplBlock (Analysis::NodeMapping mappings, + std::vector<std::unique_ptr<ImplItem>> impl_items, + std::vector<std::unique_ptr<GenericParam>> generic_params, + std::unique_ptr<Type> impl_type, + std::unique_ptr<TypePath> trait_ref, + WhereClause where_clause, BoundPolarity polarity, + Visibility vis, AST::AttrVec inner_attrs, + AST::AttrVec outer_attrs, location_t locus, bool unsafe) + : VisItem (std::move (mappings), std::move (vis), std::move (outer_attrs)), + WithInnerAttrs (std::move (inner_attrs)), + generic_params (std::move (generic_params)), + impl_type (std::move (impl_type)), trait_ref (std::move (trait_ref)), + where_clause (std::move (where_clause)), polarity (polarity), locus (locus), + impl_items (std::move (impl_items)), unsafe (unsafe) +{} + +ImplBlock::ImplBlock (ImplBlock const &other) + : VisItem (other), WithInnerAttrs (other.inner_attrs), + impl_type (other.impl_type->clone_type ()), + where_clause (other.where_clause), polarity (other.polarity), + locus (other.locus), unsafe (other.unsafe) +{ + generic_params.reserve (other.generic_params.size ()); + for (const auto &e : other.generic_params) + generic_params.push_back (e->clone_generic_param ()); + + impl_items.reserve (other.impl_items.size ()); + for (const auto &e : other.impl_items) + impl_items.push_back (e->clone_inherent_impl_item ()); +} + +ImplBlock & +ImplBlock::operator= (ImplBlock const &other) +{ + VisItem::operator= (other); + impl_type = other.impl_type->clone_type (); + where_clause = other.where_clause; + polarity = other.polarity; + inner_attrs = other.inner_attrs; + locus = other.locus; + unsafe = other.unsafe; + + generic_params.reserve (other.generic_params.size ()); + for (const auto &e : other.generic_params) + generic_params.push_back (e->clone_generic_param ()); + + impl_items.reserve (other.impl_items.size ()); + for (const auto &e : other.impl_items) + impl_items.push_back (e->clone_inherent_impl_item ()); + + return *this; +} + +ExternalItem::ExternalItem (Analysis::NodeMapping mappings, + Identifier item_name, Visibility vis, + AST::AttrVec outer_attrs, location_t locus) + : mappings (mappings), outer_attrs (std::move (outer_attrs)), + visibility (std::move (vis)), item_name (std::move (item_name)), + locus (locus) +{} + +ExternalItem::ExternalItem (ExternalItem const &other) + : mappings (other.mappings), outer_attrs (other.outer_attrs), + visibility (other.visibility), item_name (other.item_name), + locus (other.locus) +{} + +ExternalItem & +ExternalItem::operator= (ExternalItem const &other) +{ + mappings = other.mappings; + item_name = other.item_name; + visibility = other.visibility; + outer_attrs = other.outer_attrs; + locus = other.locus; + + return *this; +} + +ExternalStaticItem::ExternalStaticItem (Analysis::NodeMapping mappings, + Identifier item_name, + std::unique_ptr<Type> item_type, + Mutability mut, Visibility vis, + AST::AttrVec outer_attrs, + location_t locus) + : ExternalItem (std::move (mappings), std::move (item_name), std::move (vis), + std::move (outer_attrs), locus), + mut (mut), item_type (std::move (item_type)) +{} + +ExternalStaticItem::ExternalStaticItem (ExternalStaticItem const &other) + : ExternalItem (other), mut (other.mut), + item_type (other.item_type->clone_type ()) +{} + +ExternalStaticItem & +ExternalStaticItem::operator= (ExternalStaticItem const &other) +{ + ExternalItem::operator= (other); + item_type = other.item_type->clone_type (); + mut = other.mut; + + return *this; +} + +NamedFunctionParam::NamedFunctionParam (Analysis::NodeMapping mappings, + Identifier name, + std::unique_ptr<Type> param_type) + : name (std::move (name)), param_type (std::move (param_type)), + mappings (std::move (mappings)) +{} + +NamedFunctionParam::NamedFunctionParam (NamedFunctionParam const &other) + : name (other.name), param_type (other.param_type->clone_type ()), + mappings (other.mappings) +{} + +NamedFunctionParam & +NamedFunctionParam::operator= (NamedFunctionParam const &other) +{ + mappings = other.mappings; + name = other.name; + param_type = other.param_type->clone_type (); + // has_name = other.has_name; + + return *this; +} + +ExternalFunctionItem::ExternalFunctionItem ( + Analysis::NodeMapping mappings, Identifier item_name, + std::vector<std::unique_ptr<GenericParam>> generic_params, + std::unique_ptr<Type> return_type, WhereClause where_clause, + std::vector<NamedFunctionParam> function_params, bool has_variadics, + Visibility vis, AST::AttrVec outer_attrs, location_t locus) + : ExternalItem (std::move (mappings), std::move (item_name), std::move (vis), + std::move (outer_attrs), locus), + generic_params (std::move (generic_params)), + return_type (std::move (return_type)), + where_clause (std::move (where_clause)), + function_params (std::move (function_params)), has_variadics (has_variadics) +{} + +ExternalFunctionItem::ExternalFunctionItem (ExternalFunctionItem const &other) + : ExternalItem (other), where_clause (other.where_clause), + function_params (other.function_params), has_variadics (other.has_variadics) +{ + if (other.return_type) + return_type = other.return_type->clone_type (); + + generic_params.reserve (other.generic_params.size ()); + for (const auto &e : other.generic_params) + generic_params.push_back (e->clone_generic_param ()); +} + +ExternalFunctionItem & +ExternalFunctionItem::operator= (ExternalFunctionItem const &other) +{ + ExternalItem::operator= (other); + + where_clause = other.where_clause; + function_params = other.function_params; + has_variadics = other.has_variadics; + + if (other.return_type) + return_type = other.return_type->clone_type (); + + generic_params.reserve (other.generic_params.size ()); + for (const auto &e : other.generic_params) + generic_params.push_back (e->clone_generic_param ()); + + return *this; +} + +ExternalTypeItem::ExternalTypeItem (Analysis::NodeMapping mappings, + Identifier item_name, Visibility vis, + location_t locus) + : ExternalItem (std::move (mappings), std::move (item_name), + Visibility (std::move (vis)), + /* FIXME: Is that correct? */ + {}, locus) +{} + +ExternalTypeItem::ExternalTypeItem (ExternalTypeItem const &other) + : ExternalItem (other) +{} + +ExternBlock::ExternBlock ( + Analysis::NodeMapping mappings, ABI abi, + std::vector<std::unique_ptr<ExternalItem>> extern_items, Visibility vis, + AST::AttrVec inner_attrs, AST::AttrVec outer_attrs, location_t locus) + : VisItem (std::move (mappings), std::move (vis), std::move (outer_attrs)), + WithInnerAttrs (std::move (inner_attrs)), abi (abi), + extern_items (std::move (extern_items)), locus (locus) +{} + +ExternBlock::ExternBlock (ExternBlock const &other) + : VisItem (other), WithInnerAttrs (other.inner_attrs), abi (other.abi), + locus (other.locus) +{ + extern_items.reserve (other.extern_items.size ()); + for (const auto &e : other.extern_items) + extern_items.push_back (e->clone_external_item ()); +} + +ExternBlock & +ExternBlock::operator= (ExternBlock const &other) +{ + VisItem::operator= (other); + abi = other.abi; + inner_attrs = other.inner_attrs; + locus = other.locus; + + extern_items.reserve (other.extern_items.size ()); + for (const auto &e : other.extern_items) + extern_items.push_back (e->clone_external_item ()); + + return *this; +} + +} // namespace HIR +} // namespace Rust diff --git a/gcc/rust/hir/tree/rust-hir-item.h b/gcc/rust/hir/tree/rust-hir-item.h index a06513d..37f599c 100644 --- a/gcc/rust/hir/tree/rust-hir-item.h +++ b/gcc/rust/hir/tree/rust-hir-item.h @@ -19,25 +19,82 @@ #ifndef RUST_HIR_ITEM_H #define RUST_HIR_ITEM_H +#include "optional.h" #include "rust-abi.h" -#include "rust-ast-full-decls.h" +#include "rust-hir-stmt.h" #include "rust-common.h" -#include "rust-hir-expr.h" -#include "rust-hir.h" -#include "rust-hir-path.h" +#include "rust-hir-visibility.h" +#include "rust-hir-generic-param.h" +#include "rust-system.h" namespace Rust { namespace HIR { -// forward decls -class BlockExpr; -class TypePath; + +// Rust "item" HIR node (declaration of top-level/module-level allowed stuff) +class Item : public Stmt, public WithOuterAttrs +{ + // TODO: should outer attrs be defined here or in each derived class? +public: + enum class ItemKind + { + Static, + Constant, + TypeAlias, + Function, + UseDeclaration, + ExternBlock, + ExternCrate, + Struct, + Union, + Enum, + EnumItem, // FIXME: ARTHUR: Do we need that? + Trait, + Impl, + Module, + }; + + static std::string item_kind_string (ItemKind kind); + + virtual ItemKind get_item_kind () const = 0; + + // Unique pointer custom clone function + std::unique_ptr<Item> clone_item () const + { + return std::unique_ptr<Item> (clone_item_impl ()); + } + + BaseKind get_hir_kind () override { return Node::BaseKind::ITEM; } + + std::string as_string () const override; + + /* Adds crate names to the vector passed by reference, if it can + * (polymorphism). */ + virtual void + add_crate_name (std::vector<std::string> &names ATTRIBUTE_UNUSED) const + {} + + bool is_item () const override final { return true; } + +protected: + // Constructor + Item (Analysis::NodeMapping mappings, + AST::AttrVec outer_attribs = AST::AttrVec ()) + : Stmt (std::move (mappings)), WithOuterAttrs (std::move (outer_attribs)) + {} + + // Clone function implementation as pure virtual method + virtual Item *clone_item_impl () const = 0; + + /* Save having to specify two clone methods in derived classes by making + * statement clone return item clone. Hopefully won't affect performance too + * much. */ + Item *clone_stmt_impl () const override { return clone_item_impl (); } +}; // A type generic parameter (as opposed to a lifetime generic parameter) class TypeParam : public GenericParam { - // bool has_outer_attribute; - // std::unique_ptr<Attribute> outer_attr; - AST::Attribute outer_attr; + AST::AttrVec outer_attrs; Identifier type_representation; @@ -46,70 +103,37 @@ class TypeParam : public GenericParam std::vector<std::unique_ptr<TypeParamBound>> type_param_bounds; // inlined form - // bool has_type; - std::unique_ptr<Type> type; + tl::optional<std::unique_ptr<Type>> type; location_t locus; public: // Returns whether the type of the type param has been specified. - bool has_type () const { return type != nullptr; } + bool has_type () const { return type.has_value (); } // Returns whether the type param has type param bounds. bool has_type_param_bounds () const { return !type_param_bounds.empty (); } // Returns whether the type param has an outer attribute. - bool has_outer_attribute () const { return !outer_attr.is_empty (); } - AST::Attribute &get_outer_attribute () { return outer_attr; } + bool has_outer_attribute () const override { return outer_attrs.size () > 0; } + AST::AttrVec &get_outer_attrs () override { return outer_attrs; } TypeParam (Analysis::NodeMapping mappings, Identifier type_representation, location_t locus = UNDEF_LOCATION, std::vector<std::unique_ptr<TypeParamBound>> type_param_bounds = std::vector<std::unique_ptr<TypeParamBound>> (), - std::unique_ptr<Type> type = nullptr, - AST::Attribute outer_attr = AST::Attribute::create_empty ()) - : GenericParam (mappings), outer_attr (std::move (outer_attr)), - type_representation (std::move (type_representation)), - type_param_bounds (std::move (type_param_bounds)), - type (std::move (type)), locus (locus) - {} + tl::optional<std::unique_ptr<Type>> type = tl::nullopt, + AST::AttrVec outer_attrs = std::vector<AST::Attribute> ()); // Copy constructor uses clone - TypeParam (TypeParam const &other) - : GenericParam (other.mappings), outer_attr (other.outer_attr), - type_representation (other.type_representation), locus (other.locus) - { - // guard to prevent null pointer dereference - if (other.type != nullptr) - type = other.type->clone_type (); - - type_param_bounds.reserve (other.type_param_bounds.size ()); - for (const auto &e : other.type_param_bounds) - type_param_bounds.push_back (e->clone_type_param_bound ()); - } + TypeParam (TypeParam const &other); // Overloaded assignment operator to clone - TypeParam &operator= (TypeParam const &other) - { - type_representation = other.type_representation; - outer_attr = other.outer_attr; - locus = other.locus; - mappings = other.mappings; - - // guard to prevent null pointer dereference - if (other.type != nullptr) - type = other.type->clone_type (); - else - type = nullptr; - - type_param_bounds.reserve (other.type_param_bounds.size ()); - for (const auto &e : other.type_param_bounds) - type_param_bounds.push_back (e->clone_type_param_bound ()); + TypeParam &operator= (TypeParam const &other); - return *this; - } // move constructors TypeParam (TypeParam &&other) = default; + TypeParam &operator= (TypeParam &&other) = default; std::string as_string () const override; @@ -120,18 +144,15 @@ public: Identifier get_type_representation () const { return type_representation; } - std::unique_ptr<Type> &get_type () { return type; } - - Analysis::NodeMapping get_type_mappings () const + Type &get_type () { - rust_assert (type != nullptr); - return type->get_mappings (); + rust_assert (*type); + return *type.value (); } - std::vector<std::unique_ptr<TypeParamBound>> &get_type_param_bounds () - { - return type_param_bounds; - } + Analysis::NodeMapping get_type_mappings () const; + + std::vector<std::unique_ptr<TypeParamBound>> &get_type_param_bounds (); protected: // Clone function implementation as (not pure) virtual method @@ -236,35 +257,13 @@ public: Analysis::NodeMapping mappings, std::vector<LifetimeParam> for_lifetimes, std::unique_ptr<Type> bound_type, std::vector<std::unique_ptr<TypeParamBound>> type_param_bounds, - location_t locus) - : for_lifetimes (std::move (for_lifetimes)), - bound_type (std::move (bound_type)), - type_param_bounds (std::move (type_param_bounds)), - mappings (std::move (mappings)), locus (locus) - {} + location_t locus); // Copy constructor requires clone - TypeBoundWhereClauseItem (TypeBoundWhereClauseItem const &other) - : for_lifetimes (other.for_lifetimes), - bound_type (other.bound_type->clone_type ()), mappings (other.mappings) - { - type_param_bounds.reserve (other.type_param_bounds.size ()); - for (const auto &e : other.type_param_bounds) - type_param_bounds.push_back (e->clone_type_param_bound ()); - } + TypeBoundWhereClauseItem (TypeBoundWhereClauseItem const &other); // Overload assignment operator to clone - TypeBoundWhereClauseItem &operator= (TypeBoundWhereClauseItem const &other) - { - mappings = other.mappings; - for_lifetimes = other.for_lifetimes; - bound_type = other.bound_type->clone_type (); - type_param_bounds.reserve (other.type_param_bounds.size ()); - for (const auto &e : other.type_param_bounds) - type_param_bounds.push_back (e->clone_type_param_bound ()); - - return *this; - } + TypeBoundWhereClauseItem &operator= (TypeBoundWhereClauseItem const &other); // move constructors TypeBoundWhereClauseItem (TypeBoundWhereClauseItem &&other) = default; @@ -279,12 +278,9 @@ public: std::vector<LifetimeParam> &get_for_lifetimes () { return for_lifetimes; } - std::unique_ptr<Type> &get_bound_type () { return bound_type; } + Type &get_bound_type () { return *bound_type; } - std::vector<std::unique_ptr<TypeParamBound>> &get_type_param_bounds () - { - return type_param_bounds; - } + std::vector<std::unique_ptr<TypeParamBound>> &get_type_param_bounds (); Analysis::NodeMapping get_mappings () const override final { @@ -375,78 +371,40 @@ public: private: ImplicitSelfKind self_kind; - Lifetime lifetime; + tl::optional<Lifetime> lifetime; std::unique_ptr<Type> type; location_t locus; Analysis::NodeMapping mappings; SelfParam (Analysis::NodeMapping mappings, ImplicitSelfKind self_kind, - Lifetime lifetime, Type *type) - : self_kind (self_kind), lifetime (std::move (lifetime)), type (type), - mappings (mappings) - {} + tl::optional<Lifetime> lifetime, Type *type); public: // Type-based self parameter (not ref, no lifetime) SelfParam (Analysis::NodeMapping mappings, std::unique_ptr<Type> type, - bool is_mut, location_t locus) - : self_kind (is_mut ? ImplicitSelfKind::MUT : ImplicitSelfKind::IMM), - lifetime ( - Lifetime (mappings, AST::Lifetime::LifetimeType::NAMED, "", locus)), - type (std::move (type)), locus (locus), mappings (mappings) - {} + bool is_mut, location_t locus); // Lifetime-based self parameter (is ref, no type) - SelfParam (Analysis::NodeMapping mappings, Lifetime lifetime, bool is_mut, - location_t locus) - : self_kind (is_mut ? ImplicitSelfKind::MUT_REF - : ImplicitSelfKind::IMM_REF), - lifetime (std::move (lifetime)), locus (locus), mappings (mappings) - {} + SelfParam (Analysis::NodeMapping mappings, tl::optional<Lifetime> lifetime, + bool is_mut, location_t locus); // Copy constructor requires clone - SelfParam (SelfParam const &other) - : self_kind (other.self_kind), lifetime (other.lifetime), - locus (other.locus), mappings (other.mappings) - { - if (other.type != nullptr) - type = other.type->clone_type (); - } + SelfParam (SelfParam const &other); // Overload assignment operator to use clone - SelfParam &operator= (SelfParam const &other) - { - if (other.type != nullptr) - type = other.type->clone_type (); - - self_kind = other.self_kind; - lifetime = other.lifetime; - locus = other.locus; - mappings = other.mappings; - - return *this; - } + SelfParam &operator= (SelfParam const &other); // move constructors SelfParam (SelfParam &&other) = default; SelfParam &operator= (SelfParam &&other) = default; - static SelfParam error () - { - return SelfParam (Analysis::NodeMapping::get_error (), - ImplicitSelfKind::NONE, Lifetime::error (), nullptr); - } - // Returns whether the self-param has a type field. bool has_type () const { return type != nullptr; } // Returns whether the self-param has a valid lifetime. - bool has_lifetime () const { return !lifetime.is_error (); } - - const Lifetime &get_lifetime () const { return lifetime; } + bool has_lifetime () const { return lifetime.has_value (); } - // Returns whether the self-param is in an error state. - bool is_error () const { return self_kind == ImplicitSelfKind::NONE; } + const Lifetime &get_lifetime () const { return lifetime.value (); } std::string as_string () const; @@ -454,29 +412,19 @@ public: ImplicitSelfKind get_self_kind () const { return self_kind; } - std::unique_ptr<Type> &get_type () { return type; } + Type &get_type () + { + rust_assert (type); + return *type; + } Analysis::NodeMapping get_mappings () { return mappings; } - Mutability get_mut () const - { - return (self_kind == ImplicitSelfKind::MUT - || self_kind == ImplicitSelfKind::MUT_REF) - ? Mutability::Mut - : Mutability::Imm; - } + Mutability get_mut () const; - bool is_mut () const - { - return self_kind == ImplicitSelfKind::MUT - || self_kind == ImplicitSelfKind::MUT_REF; - } + bool is_mut () const; - bool is_ref () const - { - return self_kind == ImplicitSelfKind::IMM_REF - || self_kind == ImplicitSelfKind::MUT_REF; - } + bool is_ref () const; }; // Qualifiers for function, i.e. const, unsafe, extern etc. @@ -518,28 +466,13 @@ struct FunctionParam public: FunctionParam (Analysis::NodeMapping mappings, std::unique_ptr<Pattern> param_name, - std::unique_ptr<Type> param_type, location_t locus) - : param_name (std::move (param_name)), type (std::move (param_type)), - locus (locus), mappings (mappings) - {} + std::unique_ptr<Type> param_type, location_t locus); // Copy constructor uses clone - FunctionParam (FunctionParam const &other) - : param_name (other.param_name->clone_pattern ()), - type (other.type->clone_type ()), locus (other.locus), - mappings (other.mappings) - {} + FunctionParam (FunctionParam const &other); // Overload assignment operator to use clone - FunctionParam &operator= (FunctionParam const &other) - { - param_name = other.param_name->clone_pattern (); - type = other.type->clone_type (); - locus = other.locus; - mappings = other.mappings; - - return *this; - } + FunctionParam &operator= (FunctionParam const &other); // move constructors FunctionParam (FunctionParam &&other) = default; @@ -549,63 +482,15 @@ public: location_t get_locus () const { return locus; } - std::unique_ptr<Pattern> &get_param_name () { return param_name; } - - std::unique_ptr<Type> &get_type () { return type; } + Pattern &get_param_name () { return *param_name; } - const Analysis::NodeMapping &get_mappings () const { return mappings; } -}; - -// Visibility of an item -struct Visibility -{ -public: - enum VisType + Type &get_type () { - PRIVATE, - PUBLIC, - RESTRICTED, - ERROR, - }; - -private: - VisType vis_type; - HIR::SimplePath path; - location_t locus; - - // should this store location info? - -public: - Visibility (VisType vis_type, - HIR::SimplePath path = HIR::SimplePath::create_empty (), - location_t locus = UNDEF_LOCATION) - : vis_type (vis_type), path (std::move (path)), locus (locus) - {} - - // Returns whether visibility is in an error state. - bool is_error () const { return vis_type == ERROR; } - - // Does the current visibility refer to a simple `pub <item>` entirely public - bool is_public () const { return vis_type == PUBLIC; } - - // Is the current visibility public restricted to a certain path - bool is_restricted () const { return vis_type == RESTRICTED; } - - // Creates an error visibility. - static Visibility create_error () - { - return Visibility (ERROR, HIR::SimplePath::create_empty ()); + rust_assert (type); + return *type; } - VisType get_vis_type () const { return vis_type; } - - const HIR::SimplePath &get_path () const - { - rust_assert (!is_error ()); - return path; - } - - std::string as_string () const; + const Analysis::NodeMapping &get_mappings () const { return mappings; } }; // Item that supports visibility - abstract base class @@ -622,18 +507,10 @@ protected: {} // Visibility copy constructor - VisItem (VisItem const &other) : Item (other), visibility (other.visibility) - {} + VisItem (VisItem const &other); // Overload assignment operator to clone - VisItem &operator= (VisItem const &other) - { - Item::operator= (other); - visibility = other.visibility; - // outer_attrs = other.outer_attrs; - - return *this; - } + VisItem &operator= (VisItem const &other); // move constructors VisItem (VisItem &&other) = default; @@ -675,34 +552,13 @@ public: location_t locus, std::vector<std::unique_ptr<Item>> items, Visibility visibility = Visibility::create_error (), AST::AttrVec inner_attrs = AST::AttrVec (), - AST::AttrVec outer_attrs = AST::AttrVec ()) - : VisItem (std::move (mappings), std::move (visibility), - std::move (outer_attrs)), - WithInnerAttrs (std::move (inner_attrs)), module_name (module_name), - locus (locus), items (std::move (items)) - {} + AST::AttrVec outer_attrs = AST::AttrVec ()); // Copy constructor with vector clone - Module (Module const &other) - : VisItem (other), WithInnerAttrs (other.inner_attrs), module_name ("") - { - items.reserve (other.items.size ()); - for (const auto &e : other.items) - items.push_back (e->clone_item ()); - } + Module (Module const &other); // Overloaded assignment operator with vector clone - Module &operator= (Module const &other) - { - VisItem::operator= (other); - inner_attrs = other.inner_attrs; - - items.reserve (other.items.size ()); - for (const auto &e : other.items) - items.push_back (e->clone_item ()); - - return *this; - } + Module &operator= (Module const &other); // move constructors Module (Module &&other) = default; @@ -1058,7 +914,7 @@ public: location_t get_locus () const override final { return locus; } ItemKind get_item_kind () const override { return ItemKind::UseDeclaration; } - std::unique_ptr<UseTree> &get_use_tree () { return use_tree; } + UseTree &get_use_tree () { return *use_tree; } void accept_vis (HIRFullVisitor &vis) override; void accept_vis (HIRStmtVisitor &vis) override; void accept_vis (HIRVisItemVisitor &vis) override; @@ -1080,6 +936,12 @@ protected: class LetStmt; +enum class Defaultness +{ + Default, + Final, +}; + // Rust function declaration HIR node class Function : public VisItem, public ImplItem { @@ -1090,9 +952,14 @@ class Function : public VisItem, public ImplItem std::unique_ptr<Type> return_type; WhereClause where_clause; std::unique_ptr<BlockExpr> function_body; - SelfParam self; + tl::optional<SelfParam> self; location_t locus; + // NOTE: This should be moved to the trait item base class once we start + // implementing specialization for real, instead of just stubbing out the + // feature + Defaultness defaultness; + public: std::string as_string () const override; @@ -1108,6 +975,9 @@ public: // Returns whether function has a where clause. bool has_where_clause () const { return !where_clause.is_empty (); } + // Returns whether function has a default qualifier + bool is_default () const { return defaultness == Defaultness::Default; } + ImplItemType get_impl_item_type () const override final { return ImplItem::ImplItemType::FUNCTION; @@ -1122,63 +992,14 @@ public: std::vector<FunctionParam> function_params, std::unique_ptr<Type> return_type, WhereClause where_clause, std::unique_ptr<BlockExpr> function_body, Visibility vis, - AST::AttrVec outer_attrs, SelfParam self, location_t locus) - : VisItem (std::move (mappings), std::move (vis), std::move (outer_attrs)), - qualifiers (std::move (qualifiers)), - function_name (std::move (function_name)), - generic_params (std::move (generic_params)), - function_params (std::move (function_params)), - return_type (std::move (return_type)), - where_clause (std::move (where_clause)), - function_body (std::move (function_body)), self (std::move (self)), - locus (locus) - {} + AST::AttrVec outer_attrs, tl::optional<SelfParam> self, + Defaultness defaultness, location_t locus); // Copy constructor with clone - Function (Function const &other) - : VisItem (other), qualifiers (other.qualifiers), - function_name (other.function_name), - function_params (other.function_params), - where_clause (other.where_clause), - function_body (other.function_body->clone_block_expr ()), - self (other.self), locus (other.locus) - { - // guard to prevent null dereference (always required) - if (other.return_type != nullptr) - return_type = other.return_type->clone_type (); - else - return_type = nullptr; - - generic_params.reserve (other.generic_params.size ()); - for (const auto &e : other.generic_params) - generic_params.push_back (e->clone_generic_param ()); - } + Function (Function const &other); // Overloaded assignment operator to clone - Function &operator= (Function const &other) - { - VisItem::operator= (other); - function_name = other.function_name; - qualifiers = other.qualifiers; - function_params = other.function_params; - - // guard to prevent null dereference (always required) - if (other.return_type != nullptr) - return_type = other.return_type->clone_type (); - else - return_type = nullptr; - - where_clause = other.where_clause; - function_body = other.function_body->clone_block_expr (); - locus = other.locus; - self = other.self; - - generic_params.reserve (other.generic_params.size ()); - for (const auto &e : other.generic_params) - generic_params.push_back (e->clone_generic_param ()); - - return *this; - } + Function &operator= (Function const &other); // move constructors Function (Function &&other) = default; @@ -1212,7 +1033,7 @@ public: } // TODO: is this better? Or is a "vis_block" better? - std::unique_ptr<BlockExpr> &get_definition () { return function_body; } + BlockExpr &get_definition () { return *function_body; } const FunctionQualifiers &get_qualifiers () const { return qualifiers; } @@ -1224,11 +1045,15 @@ public: bool has_return_type () const { return return_type != nullptr; } // TODO: is this better? Or is a "vis_block" better? - std::unique_ptr<Type> &get_return_type () { return return_type; } + Type &get_return_type () { return *return_type; } - bool is_method () const { return !self.is_error (); } + bool is_method () const { return self.has_value (); } - SelfParam &get_self_param () { return self; } + tl::optional<SelfParam> &get_self_param () { return self; } + const tl::optional<SelfParam> &get_self_param () const { return self; } + + SelfParam &get_self_param_unchecked () { return self.value (); } + const SelfParam &get_self_param_unchecked () const { return self.value (); } std::string get_impl_item_name () const override final { @@ -1282,40 +1107,13 @@ public: TypeAlias (Analysis::NodeMapping mappings, Identifier new_type_name, std::vector<std::unique_ptr<GenericParam>> generic_params, WhereClause where_clause, std::unique_ptr<Type> existing_type, - Visibility vis, AST::AttrVec outer_attrs, location_t locus) - : VisItem (std::move (mappings), std::move (vis), std::move (outer_attrs)), - new_type_name (std::move (new_type_name)), - generic_params (std::move (generic_params)), - where_clause (std::move (where_clause)), - existing_type (std::move (existing_type)), locus (locus) - {} + Visibility vis, AST::AttrVec outer_attrs, location_t locus); // Copy constructor - TypeAlias (TypeAlias const &other) - : VisItem (other), new_type_name (other.new_type_name), - where_clause (other.where_clause), - existing_type (other.existing_type->clone_type ()), locus (other.locus) - { - generic_params.reserve (other.generic_params.size ()); - for (const auto &e : other.generic_params) - generic_params.push_back (e->clone_generic_param ()); - } + TypeAlias (TypeAlias const &other); // Overloaded assignment operator to clone - TypeAlias &operator= (TypeAlias const &other) - { - VisItem::operator= (other); - new_type_name = other.new_type_name; - where_clause = other.where_clause; - existing_type = other.existing_type->clone_type (); - locus = other.locus; - - generic_params.reserve (other.generic_params.size ()); - for (const auto &e : other.generic_params) - generic_params.push_back (e->clone_generic_param ()); - - return *this; - } + TypeAlias &operator= (TypeAlias const &other); // move constructors TypeAlias (TypeAlias &&other) = default; @@ -1339,7 +1137,11 @@ public: WhereClause &get_where_clause () { return where_clause; } - std::unique_ptr<Type> &get_type_aliased () { return existing_type; } + Type &get_type_aliased () + { + rust_assert (existing_type); + return *existing_type; + } Identifier get_new_type_name () const { return new_type_name; } @@ -1470,32 +1272,15 @@ public: StructField (Analysis::NodeMapping mappings, Identifier field_name, std::unique_ptr<Type> field_type, Visibility vis, - location_t locus, AST::AttrVec outer_attrs = AST::AttrVec ()) - : outer_attrs (std::move (outer_attrs)), visibility (std::move (vis)), - field_name (std::move (field_name)), field_type (std::move (field_type)), - mappings (mappings), locus (locus) - {} + location_t locus, AST::AttrVec outer_attrs = AST::AttrVec ()); // Copy constructor - StructField (StructField const &other) - : outer_attrs (other.outer_attrs), visibility (other.visibility), - field_name (other.field_name), - field_type (other.field_type->clone_type ()), mappings (other.mappings) - {} + StructField (StructField const &other); ~StructField () = default; // Overloaded assignment operator to clone - StructField &operator= (StructField const &other) - { - field_name = other.field_name; - field_type = other.field_type->clone_type (); - visibility = other.visibility; - outer_attrs = other.outer_attrs; - mappings = other.mappings; - - return *this; - } + StructField &operator= (StructField const &other); // move constructors StructField (StructField &&other) = default; @@ -1505,7 +1290,7 @@ public: Identifier get_field_name () const { return field_name; } - std::unique_ptr<Type> &get_field_type () { return field_type; } + Type &get_field_type () { return *field_type; } Analysis::NodeMapping get_mappings () const { return mappings; } @@ -1600,31 +1385,15 @@ public: // Complete constructor TupleField (Analysis::NodeMapping mapping, std::unique_ptr<Type> field_type, Visibility vis, location_t locus, - AST::AttrVec outer_attrs = AST::AttrVec ()) - : outer_attrs (std::move (outer_attrs)), visibility (std::move (vis)), - field_type (std::move (field_type)), locus (locus), mappings (mapping) - {} + AST::AttrVec outer_attrs = AST::AttrVec ()); // Copy constructor with clone - TupleField (TupleField const &other) - : outer_attrs (other.outer_attrs), visibility (other.visibility), - field_type (other.field_type->clone_type ()), locus (other.locus), - mappings (other.mappings) - {} + TupleField (TupleField const &other); ~TupleField () = default; // Overloaded assignment operator to clone - TupleField &operator= (TupleField const &other) - { - field_type = other.field_type->clone_type (); - visibility = other.visibility; - outer_attrs = other.outer_attrs; - locus = other.locus; - mappings = other.mappings; - - return *this; - } + TupleField &operator= (TupleField const &other); // move constructors TupleField (TupleField &&other) = default; @@ -1642,7 +1411,7 @@ public: location_t get_locus () const { return locus; } AST::AttrVec &get_outer_attrs () { return outer_attrs; } - std::unique_ptr<HIR::Type> &get_field_type () { return field_type; } + HIR::Type &get_field_type () { return *field_type; } }; // Rust tuple declared using struct keyword HIR node @@ -1658,12 +1427,7 @@ public: Identifier struct_name, std::vector<std::unique_ptr<GenericParam>> generic_params, WhereClause where_clause, Visibility vis, - AST::AttrVec outer_attrs, location_t locus) - : Struct (std::move (mappings), std::move (struct_name), - std::move (generic_params), std::move (where_clause), - std::move (vis), locus, std::move (outer_attrs)), - fields (std::move (fields)) - {} + AST::AttrVec outer_attrs, location_t locus); void accept_vis (HIRFullVisitor &vis) override; void accept_vis (HIRStmtVisitor &vis) override; @@ -1708,10 +1472,7 @@ public: }; EnumItem (Analysis::NodeMapping mappings, Identifier variant_name, - AST::AttrVec outer_attrs, location_t locus) - : Item (std::move (mappings), std::move (outer_attrs)), - variant_name (std::move (variant_name)), locus (locus) - {} + AST::AttrVec outer_attrs, location_t locus); // Unique pointer custom clone function std::unique_ptr<EnumItem> clone_enum_item () const @@ -1754,11 +1515,7 @@ public: EnumItemTuple (Analysis::NodeMapping mappings, Identifier variant_name, std::vector<TupleField> tuple_fields, AST::AttrVec outer_attrs, - location_t locus) - : EnumItem (std::move (mappings), std::move (variant_name), - std::move (outer_attrs), locus), - tuple_fields (std::move (tuple_fields)) - {} + location_t locus); std::string as_string () const override; @@ -1792,11 +1549,7 @@ public: EnumItemStruct (Analysis::NodeMapping mappings, Identifier variant_name, std::vector<StructField> struct_fields, - AST::AttrVec outer_attrs, location_t locus) - : EnumItem (std::move (mappings), std::move (variant_name), - std::move (outer_attrs), locus), - struct_fields (std::move (struct_fields)) - {} + AST::AttrVec outer_attrs, location_t locus); std::string as_string () const override; @@ -1821,27 +1574,13 @@ class EnumItemDiscriminant : public EnumItem public: EnumItemDiscriminant (Analysis::NodeMapping mappings, Identifier variant_name, std::unique_ptr<Expr> expr, AST::AttrVec outer_attrs, - location_t locus) - : EnumItem (std::move (mappings), std::move (variant_name), - std::move (outer_attrs), locus), - expression (std::move (expr)) - {} + location_t locus); // Copy constructor with clone - EnumItemDiscriminant (EnumItemDiscriminant const &other) - : EnumItem (other), expression (other.expression->clone_expr ()) - {} + EnumItemDiscriminant (EnumItemDiscriminant const &other); // Overloaded assignment operator to clone - EnumItemDiscriminant &operator= (EnumItemDiscriminant const &other) - { - EnumItem::operator= (other); - expression = other.expression->clone_expr (); - // variant_name = other.variant_name; - // outer_attrs = other.outer_attrs; - - return *this; - } + EnumItemDiscriminant &operator= (EnumItemDiscriminant const &other); // move constructors EnumItemDiscriminant (EnumItemDiscriminant &&other) = default; @@ -1857,7 +1596,12 @@ public: void accept_vis (HIRFullVisitor &vis) override; void accept_vis (HIRStmtVisitor &vis) override; - std::unique_ptr<Expr> &get_discriminant_expression () { return expression; } + Expr &get_discriminant_expression () { return *expression; } + + std::unique_ptr<Expr> take_discriminant_expression () + { + return std::move (expression); + } protected: // Clone function implementation as (not pure) virtual method @@ -1900,48 +1644,15 @@ public: Enum (Analysis::NodeMapping mappings, Identifier enum_name, Visibility vis, std::vector<std::unique_ptr<GenericParam>> generic_params, WhereClause where_clause, std::vector<std::unique_ptr<EnumItem>> items, - AST::AttrVec outer_attrs, location_t locus) - : VisItem (std::move (mappings), std::move (vis), std::move (outer_attrs)), - enum_name (std::move (enum_name)), - generic_params (std::move (generic_params)), - where_clause (std::move (where_clause)), items (std::move (items)), - locus (locus) - {} + AST::AttrVec outer_attrs, location_t locus); // TODO: constructor with less arguments // Copy constructor with vector clone - Enum (Enum const &other) - : VisItem (other), enum_name (other.enum_name), - where_clause (other.where_clause), locus (other.locus) - { - generic_params.reserve (other.generic_params.size ()); - for (const auto &e : other.generic_params) - generic_params.push_back (e->clone_generic_param ()); - - items.reserve (other.items.size ()); - for (const auto &e : other.items) - items.push_back (e->clone_enum_item ()); - } + Enum (Enum const &other); // Overloaded assignment operator with vector clone - Enum &operator= (Enum const &other) - { - VisItem::operator= (other); - enum_name = other.enum_name; - where_clause = other.where_clause; - locus = other.locus; - - generic_params.reserve (other.generic_params.size ()); - for (const auto &e : other.generic_params) - generic_params.push_back (e->clone_generic_param ()); - - items.reserve (other.items.size ()); - for (const auto &e : other.items) - items.push_back (e->clone_enum_item ()); - - return *this; - } + Enum &operator= (Enum const &other); // Move constructors Enum (Enum &&other) = default; @@ -2009,40 +1720,13 @@ public: Union (Analysis::NodeMapping mappings, Identifier union_name, Visibility vis, std::vector<std::unique_ptr<GenericParam>> generic_params, WhereClause where_clause, std::vector<StructField> variants, - AST::AttrVec outer_attrs, location_t locus) - : VisItem (std::move (mappings), std::move (vis), std::move (outer_attrs)), - union_name (std::move (union_name)), - generic_params (std::move (generic_params)), - where_clause (std::move (where_clause)), variants (std::move (variants)), - locus (locus) - {} + AST::AttrVec outer_attrs, location_t locus); // copy constructor with vector clone - Union (Union const &other) - : VisItem (other), union_name (other.union_name), - where_clause (other.where_clause), variants (other.variants), - locus (other.locus) - { - generic_params.reserve (other.generic_params.size ()); - for (const auto &e : other.generic_params) - generic_params.push_back (e->clone_generic_param ()); - } + Union (Union const &other); // overloaded assignment operator with vector clone - Union &operator= (Union const &other) - { - VisItem::operator= (other); - union_name = other.union_name; - where_clause = other.where_clause; - variants = other.variants; - locus = other.locus; - - generic_params.reserve (other.generic_params.size ()); - for (const auto &e : other.generic_params) - generic_params.push_back (e->clone_generic_param ()); - - return *this; - } + Union &operator= (Union const &other); // move constructors Union (Union &&other) = default; @@ -2086,29 +1770,12 @@ public: ConstantItem (Analysis::NodeMapping mappings, Identifier ident, Visibility vis, std::unique_ptr<Type> type, std::unique_ptr<Expr> const_expr, AST::AttrVec outer_attrs, - location_t locus) - : VisItem (std::move (mappings), std::move (vis), std::move (outer_attrs)), - identifier (std::move (ident)), type (std::move (type)), - const_expr (std::move (const_expr)), locus (locus) - {} + location_t locus); - ConstantItem (ConstantItem const &other) - : VisItem (other), identifier (other.identifier), - type (other.type->clone_type ()), - const_expr (other.const_expr->clone_expr ()), locus (other.locus) - {} + ConstantItem (ConstantItem const &other); // Overload assignment operator to clone - ConstantItem &operator= (ConstantItem const &other) - { - VisItem::operator= (other); - identifier = other.identifier; - type = other.type->clone_type (); - const_expr = other.const_expr->clone_expr (); - locus = other.locus; - - return *this; - } + ConstantItem &operator= (ConstantItem const &other); // move constructors ConstantItem (ConstantItem &&other) = default; @@ -2128,9 +1795,13 @@ public: void accept_vis (HIRImplVisitor &vis) override; void accept_vis (HIRVisItemVisitor &vis) override; - std::unique_ptr<Type> &get_type () { return type; } + Type &get_type () + { + rust_assert (type); + return *type; + } - std::unique_ptr<Expr> &get_expr () { return const_expr; } + Expr &get_expr () { return *const_expr; } Identifier get_identifier () const { return identifier; } @@ -2182,31 +1853,13 @@ public: StaticItem (Analysis::NodeMapping mappings, Identifier name, Mutability mut, std::unique_ptr<Type> type, std::unique_ptr<Expr> expr, - Visibility vis, AST::AttrVec outer_attrs, location_t locus) - : VisItem (std::move (mappings), std::move (vis), std::move (outer_attrs)), - mut (mut), name (std::move (name)), type (std::move (type)), - expr (std::move (expr)), locus (locus) - {} + Visibility vis, AST::AttrVec outer_attrs, location_t locus); // Copy constructor with clone - StaticItem (StaticItem const &other) - : VisItem (other), mut (other.mut), name (other.name), - type (other.type->clone_type ()), expr (other.expr->clone_expr ()), - locus (other.locus) - {} + StaticItem (StaticItem const &other); // Overloaded assignment operator to clone - StaticItem &operator= (StaticItem const &other) - { - VisItem::operator= (other); - name = other.name; - mut = other.mut; - type = other.type->clone_type (); - expr = other.expr->clone_expr (); - locus = other.locus; - - return *this; - } + StaticItem &operator= (StaticItem const &other); // move constructors StaticItem (StaticItem &&other) = default; @@ -2224,9 +1877,17 @@ public: bool is_mut () const { return mut == Mutability::Mut; } - std::unique_ptr<Expr> &get_expr () { return expr; } + Expr &get_expr () + { + rust_assert (expr); + return *expr; + } - std::unique_ptr<Type> &get_type () { return type; } + Type &get_type () + { + rust_assert (type); + return *type; + } ItemKind get_item_kind () const override { return ItemKind::Static; } @@ -2247,53 +1908,24 @@ private: std::vector<FunctionParam> function_params; std::unique_ptr<Type> return_type; WhereClause where_clause; - SelfParam self; + tl::optional<SelfParam> self; public: // Mega-constructor TraitFunctionDecl (Identifier function_name, FunctionQualifiers qualifiers, std::vector<std::unique_ptr<GenericParam>> generic_params, - SelfParam self, std::vector<FunctionParam> function_params, + tl::optional<SelfParam> self, + std::vector<FunctionParam> function_params, std::unique_ptr<Type> return_type, - WhereClause where_clause) - : qualifiers (std::move (qualifiers)), - function_name (std::move (function_name)), - generic_params (std::move (generic_params)), - function_params (std::move (function_params)), - return_type (std::move (return_type)), - where_clause (std::move (where_clause)), self (std::move (self)) - {} + WhereClause where_clause); // Copy constructor with clone - TraitFunctionDecl (TraitFunctionDecl const &other) - : qualifiers (other.qualifiers), function_name (other.function_name), - function_params (other.function_params), - return_type (other.return_type->clone_type ()), - where_clause (other.where_clause), self (other.self) - { - generic_params.reserve (other.generic_params.size ()); - for (const auto &e : other.generic_params) - generic_params.push_back (e->clone_generic_param ()); - } + TraitFunctionDecl (TraitFunctionDecl const &other); ~TraitFunctionDecl () = default; // Overloaded assignment operator with clone - TraitFunctionDecl &operator= (TraitFunctionDecl const &other) - { - function_name = other.function_name; - qualifiers = other.qualifiers; - function_params = other.function_params; - return_type = other.return_type->clone_type (); - where_clause = other.where_clause; - self = other.self; - - generic_params.reserve (other.generic_params.size ()); - for (const auto &e : other.generic_params) - generic_params.push_back (e->clone_generic_param ()); - - return *this; - } + TraitFunctionDecl &operator= (TraitFunctionDecl const &other); // move constructors TraitFunctionDecl (TraitFunctionDecl &&other) = default; @@ -2315,9 +1947,13 @@ public: WhereClause &get_where_clause () { return where_clause; } - bool is_method () const { return !self.is_error (); } + bool is_method () const { return self.has_value (); } + + SelfParam &get_self_unchecked () { return self.value (); } + const SelfParam &get_self_unchecked () const { return self.value (); } - SelfParam &get_self () { return self; } + tl::optional<SelfParam> &get_self () { return self; } + const tl::optional<SelfParam> &get_self () const { return self; } Identifier get_function_name () const { return function_name; } @@ -2326,7 +1962,7 @@ public: return generic_params; } - std::unique_ptr<Type> &get_return_type () { return return_type; } + Type &get_return_type () { return *return_type; } std::vector<FunctionParam> &get_function_params () { return function_params; } @@ -2347,34 +1983,13 @@ public: TraitItemFunc (Analysis::NodeMapping mappings, TraitFunctionDecl decl, std::unique_ptr<BlockExpr> block_expr, - AST::AttrVec outer_attrs, location_t locus) - : TraitItem (mappings), outer_attrs (std::move (outer_attrs)), - decl (std::move (decl)), block_expr (std::move (block_expr)), - locus (locus) - {} + AST::AttrVec outer_attrs, location_t locus); // Copy constructor with clone - TraitItemFunc (TraitItemFunc const &other) - : TraitItem (other.mappings), outer_attrs (other.outer_attrs), - decl (other.decl), locus (other.locus) - { - if (other.block_expr != nullptr) - block_expr = other.block_expr->clone_block_expr (); - } + TraitItemFunc (TraitItemFunc const &other); // Overloaded assignment operator to clone - TraitItemFunc &operator= (TraitItemFunc const &other) - { - TraitItem::operator= (other); - outer_attrs = other.outer_attrs; - decl = other.decl; - locus = other.locus; - mappings = other.mappings; - if (other.block_expr != nullptr) - block_expr = other.block_expr->clone_block_expr (); - - return *this; - } + TraitItemFunc &operator= (TraitItemFunc const &other); // move constructors TraitItemFunc (TraitItemFunc &&other) = default; @@ -2391,9 +2006,7 @@ public: const TraitFunctionDecl &get_decl () const { return decl; } - bool has_block_defined () const { return block_expr != nullptr; } - - std::unique_ptr<BlockExpr> &get_block_expr () { return block_expr; } + BlockExpr &get_block_expr () { return *block_expr; } const std::string trait_identifier () const override final { @@ -2436,32 +2049,13 @@ public: TraitItemConst (Analysis::NodeMapping mappings, Identifier name, std::unique_ptr<Type> type, std::unique_ptr<Expr> expr, - AST::AttrVec outer_attrs, location_t locus) - : TraitItem (mappings), outer_attrs (std::move (outer_attrs)), - name (std::move (name)), type (std::move (type)), expr (std::move (expr)), - locus (locus) - {} + AST::AttrVec outer_attrs, location_t locus); // Copy constructor with clones - TraitItemConst (TraitItemConst const &other) - : TraitItem (other.mappings), outer_attrs (other.outer_attrs), - name (other.name), type (other.type->clone_type ()), - expr (other.expr->clone_expr ()), locus (other.locus) - {} + TraitItemConst (TraitItemConst const &other); // Overloaded assignment operator to clone - TraitItemConst &operator= (TraitItemConst const &other) - { - TraitItem::operator= (other); - outer_attrs = other.outer_attrs; - name = other.name; - type = other.type->clone_type (); - expr = other.expr->clone_expr (); - locus = other.locus; - mappings = other.mappings; - - return *this; - } + TraitItemConst &operator= (TraitItemConst const &other); // move constructors TraitItemConst (TraitItemConst &&other) = default; @@ -2476,11 +2070,21 @@ public: Identifier get_name () const { return name; } + bool has_type () const { return expr != nullptr; } + bool has_expr () const { return expr != nullptr; } - std::unique_ptr<Type> &get_type () { return type; } + Type &get_type () + { + rust_assert (type); + return *type; + } - std::unique_ptr<Expr> &get_expr () { return expr; } + Expr &get_expr () + { + rust_assert (expr); + return *expr; + } const std::string trait_identifier () const override final { @@ -2524,37 +2128,13 @@ public: TraitItemType (Analysis::NodeMapping mappings, Identifier name, std::vector<std::unique_ptr<TypeParamBound>> type_param_bounds, - AST::AttrVec outer_attrs, location_t locus) - : TraitItem (mappings), outer_attrs (std::move (outer_attrs)), - name (std::move (name)), - type_param_bounds (std::move (type_param_bounds)), locus (locus) - {} + AST::AttrVec outer_attrs, location_t locus); // Copy constructor with vector clone - TraitItemType (TraitItemType const &other) - : TraitItem (other.mappings), outer_attrs (other.outer_attrs), - name (other.name), locus (other.locus) - { - type_param_bounds.reserve (other.type_param_bounds.size ()); - for (const auto &e : other.type_param_bounds) - type_param_bounds.push_back (e->clone_type_param_bound ()); - } + TraitItemType (TraitItemType const &other); // Overloaded assignment operator with vector clone - TraitItemType &operator= (TraitItemType const &other) - { - TraitItem::operator= (other); - outer_attrs = other.outer_attrs; - name = other.name; - locus = other.locus; - mappings = other.mappings; - - type_param_bounds.reserve (other.type_param_bounds.size ()); - for (const auto &e : other.type_param_bounds) - type_param_bounds.push_back (e->clone_type_param_bound ()); - - return *this; - } + TraitItemType &operator= (TraitItemType const &other); // default move constructors TraitItemType (TraitItemType &&other) = default; @@ -2642,56 +2222,13 @@ public: std::vector<std::unique_ptr<TypeParamBound>> type_param_bounds, WhereClause where_clause, std::vector<std::unique_ptr<TraitItem>> trait_items, Visibility vis, - AST::AttrVec outer_attrs, location_t locus) - : VisItem (std::move (mappings), std::move (vis), std::move (outer_attrs)), - unsafety (unsafety), name (std::move (name)), - generic_params (std::move (generic_params)), - type_param_bounds (std::move (type_param_bounds)), - where_clause (std::move (where_clause)), - trait_items (std::move (trait_items)), locus (locus) - {} + AST::AttrVec outer_attrs, location_t locus); // Copy constructor with vector clone - Trait (Trait const &other) - : VisItem (other), unsafety (other.unsafety), name (other.name), - where_clause (other.where_clause), locus (other.locus) - { - generic_params.reserve (other.generic_params.size ()); - for (const auto &e : other.generic_params) - generic_params.push_back (e->clone_generic_param ()); - - type_param_bounds.reserve (other.type_param_bounds.size ()); - for (const auto &e : other.type_param_bounds) - type_param_bounds.push_back (e->clone_type_param_bound ()); - - trait_items.reserve (other.trait_items.size ()); - for (const auto &e : other.trait_items) - trait_items.push_back (e->clone_trait_item ()); - } + Trait (Trait const &other); // Overloaded assignment operator with vector clone - Trait &operator= (Trait const &other) - { - VisItem::operator= (other); - name = other.name; - unsafety = other.unsafety; - where_clause = other.where_clause; - locus = other.locus; - - generic_params.reserve (other.generic_params.size ()); - for (const auto &e : other.generic_params) - generic_params.push_back (e->clone_generic_param ()); - - type_param_bounds.reserve (other.type_param_bounds.size ()); - for (const auto &e : other.type_param_bounds) - type_param_bounds.push_back (e->clone_type_param_bound ()); - - trait_items.reserve (other.trait_items.size ()); - for (const auto &e : other.trait_items) - trait_items.push_back (e->clone_trait_item ()); - - return *this; - } + Trait &operator= (Trait const &other); // default move constructors Trait (Trait &&other) = default; @@ -2741,6 +2278,7 @@ class ImplBlock : public VisItem, public WithInnerAttrs BoundPolarity polarity; location_t locus; std::vector<std::unique_ptr<ImplItem>> impl_items; + bool unsafe; public: ImplBlock (Analysis::NodeMapping mappings, @@ -2749,49 +2287,11 @@ public: std::unique_ptr<Type> impl_type, std::unique_ptr<TypePath> trait_ref, WhereClause where_clause, BoundPolarity polarity, Visibility vis, AST::AttrVec inner_attrs, - AST::AttrVec outer_attrs, location_t locus) - : VisItem (std::move (mappings), std::move (vis), std::move (outer_attrs)), - WithInnerAttrs (std::move (inner_attrs)), - generic_params (std::move (generic_params)), - impl_type (std::move (impl_type)), trait_ref (std::move (trait_ref)), - where_clause (std::move (where_clause)), polarity (polarity), - locus (locus), impl_items (std::move (impl_items)) - {} - - ImplBlock (ImplBlock const &other) - : VisItem (other), WithInnerAttrs (other.inner_attrs), - impl_type (other.impl_type->clone_type ()), - where_clause (other.where_clause), polarity (other.polarity), - locus (other.locus) - { - generic_params.reserve (other.generic_params.size ()); - for (const auto &e : other.generic_params) - generic_params.push_back (e->clone_generic_param ()); + AST::AttrVec outer_attrs, location_t locus, bool unsafe = false); - impl_items.reserve (other.impl_items.size ()); - for (const auto &e : other.impl_items) - impl_items.push_back (e->clone_inherent_impl_item ()); - } + ImplBlock (ImplBlock const &other); - ImplBlock &operator= (ImplBlock const &other) - { - VisItem::operator= (other); - impl_type = other.impl_type->clone_type (); - where_clause = other.where_clause; - polarity = other.polarity; - inner_attrs = other.inner_attrs; - locus = other.locus; - - generic_params.reserve (other.generic_params.size ()); - for (const auto &e : other.generic_params) - generic_params.push_back (e->clone_generic_param ()); - - impl_items.reserve (other.impl_items.size ()); - for (const auto &e : other.impl_items) - impl_items.push_back (e->clone_inherent_impl_item ()); - - return *this; - } + ImplBlock &operator= (ImplBlock const &other); ImplBlock (ImplBlock &&other) = default; ImplBlock &operator= (ImplBlock &&other) = default; @@ -2801,6 +2301,8 @@ public: // Returns whether inherent impl block has inherent impl items. bool has_impl_items () const { return !impl_items.empty (); } + bool is_unsafe () const { return unsafe; } + void accept_vis (HIRFullVisitor &vis) override; void accept_vis (HIRStmtVisitor &vis) override; void accept_vis (HIRVisItemVisitor &vis) override; @@ -2826,7 +2328,13 @@ public: location_t get_locus () const override final { return locus; } - std::unique_ptr<Type> &get_type () { return impl_type; }; + Type &get_type () + { + rust_assert (impl_type); + return *impl_type; + }; + + bool has_type () { return impl_type != nullptr; } std::vector<std::unique_ptr<GenericParam>> &get_generic_params () { @@ -2835,7 +2343,7 @@ public: bool has_trait_ref () const { return trait_ref != nullptr; } - std::unique_ptr<TypePath> &get_trait_ref () { return trait_ref; } + TypePath &get_trait_ref () { return *trait_ref; } WhereClause &get_where_clause () { return where_clause; } @@ -2896,30 +2404,13 @@ public: protected: ExternalItem (Analysis::NodeMapping mappings, Identifier item_name, - Visibility vis, AST::AttrVec outer_attrs, location_t locus) - : mappings (mappings), outer_attrs (std::move (outer_attrs)), - visibility (std::move (vis)), item_name (std::move (item_name)), - locus (locus) - {} + Visibility vis, AST::AttrVec outer_attrs, location_t locus); // Copy constructor - ExternalItem (ExternalItem const &other) - : mappings (other.mappings), outer_attrs (other.outer_attrs), - visibility (other.visibility), item_name (other.item_name), - locus (other.locus) - {} + ExternalItem (ExternalItem const &other); // Overloaded assignment operator to clone - ExternalItem &operator= (ExternalItem const &other) - { - mappings = other.mappings; - item_name = other.item_name; - visibility = other.visibility; - outer_attrs = other.outer_attrs; - locus = other.locus; - - return *this; - } + ExternalItem &operator= (ExternalItem const &other); // move constructors ExternalItem (ExternalItem &&other) = default; @@ -2939,27 +2430,13 @@ public: ExternalStaticItem (Analysis::NodeMapping mappings, Identifier item_name, std::unique_ptr<Type> item_type, Mutability mut, Visibility vis, AST::AttrVec outer_attrs, - location_t locus) - : ExternalItem (std::move (mappings), std::move (item_name), - std::move (vis), std::move (outer_attrs), locus), - mut (mut), item_type (std::move (item_type)) - {} + location_t locus); // Copy constructor - ExternalStaticItem (ExternalStaticItem const &other) - : ExternalItem (other), mut (other.mut), - item_type (other.item_type->clone_type ()) - {} + ExternalStaticItem (ExternalStaticItem const &other); // Overloaded assignment operator to clone - ExternalStaticItem &operator= (ExternalStaticItem const &other) - { - ExternalItem::operator= (other); - item_type = other.item_type->clone_type (); - mut = other.mut; - - return *this; - } + ExternalStaticItem &operator= (ExternalStaticItem const &other); // move constructors ExternalStaticItem (ExternalStaticItem &&other) = default; @@ -2974,7 +2451,7 @@ public: Mutability get_mut () { return mut; } - std::unique_ptr<Type> &get_item_type () { return item_type; } + Type &get_item_type () { return *item_type; } ExternKind get_extern_kind () override { return ExternKind::Static; } @@ -2999,29 +2476,15 @@ public: bool has_name () const { return name.as_string () != "_"; } NamedFunctionParam (Analysis::NodeMapping mappings, Identifier name, - std::unique_ptr<Type> param_type) - : name (std::move (name)), param_type (std::move (param_type)), - mappings (std::move (mappings)) - {} + std::unique_ptr<Type> param_type); // Copy constructor - NamedFunctionParam (NamedFunctionParam const &other) - : name (other.name), param_type (other.param_type->clone_type ()), - mappings (other.mappings) - {} + NamedFunctionParam (NamedFunctionParam const &other); ~NamedFunctionParam () = default; // Overloaded assignment operator to clone - NamedFunctionParam &operator= (NamedFunctionParam const &other) - { - mappings = other.mappings; - name = other.name; - param_type = other.param_type->clone_type (); - // has_name = other.has_name; - - return *this; - } + NamedFunctionParam &operator= (NamedFunctionParam const &other); // move constructors NamedFunctionParam (NamedFunctionParam &&other) = default; @@ -3031,7 +2494,11 @@ public: Identifier get_param_name () const { return name; } - std::unique_ptr<Type> &get_type () { return param_type; } + Type &get_type () + { + rust_assert (param_type); + return *param_type; + } Analysis::NodeMapping get_mappings () const { return mappings; } }; @@ -3073,48 +2540,13 @@ public: std::vector<std::unique_ptr<GenericParam>> generic_params, std::unique_ptr<Type> return_type, WhereClause where_clause, std::vector<NamedFunctionParam> function_params, bool has_variadics, - Visibility vis, AST::AttrVec outer_attrs, location_t locus) - : ExternalItem (std::move (mappings), std::move (item_name), - std::move (vis), std::move (outer_attrs), locus), - generic_params (std::move (generic_params)), - return_type (std::move (return_type)), - where_clause (std::move (where_clause)), - function_params (std::move (function_params)), - has_variadics (has_variadics) - {} + Visibility vis, AST::AttrVec outer_attrs, location_t locus); // Copy constructor with clone - ExternalFunctionItem (ExternalFunctionItem const &other) - : ExternalItem (other), where_clause (other.where_clause), - function_params (other.function_params), - has_variadics (other.has_variadics) - { - if (other.return_type) - return_type = other.return_type->clone_type (); - - generic_params.reserve (other.generic_params.size ()); - for (const auto &e : other.generic_params) - generic_params.push_back (e->clone_generic_param ()); - } + ExternalFunctionItem (ExternalFunctionItem const &other); // Overloaded assignment operator with clone - ExternalFunctionItem &operator= (ExternalFunctionItem const &other) - { - ExternalItem::operator= (other); - - where_clause = other.where_clause; - function_params = other.function_params; - has_variadics = other.has_variadics; - - if (other.return_type) - return_type = other.return_type->clone_type (); - - generic_params.reserve (other.generic_params.size ()); - for (const auto &e : other.generic_params) - generic_params.push_back (e->clone_generic_param ()); - - return *this; - } + ExternalFunctionItem &operator= (ExternalFunctionItem const &other); // move constructors ExternalFunctionItem (ExternalFunctionItem &&other) = default; @@ -3130,7 +2562,7 @@ public: return generic_params; } - std::unique_ptr<Type> &get_return_type () { return return_type; } + Type &get_return_type () { return *return_type; } std::vector<NamedFunctionParam> &get_function_params () { @@ -3154,14 +2586,9 @@ class ExternalTypeItem : public ExternalItem { public: ExternalTypeItem (Analysis::NodeMapping mappings, Identifier item_name, - Visibility vis, location_t locus) - : ExternalItem (std::move (mappings), std::move (item_name), - Visibility (std::move (vis)), - /* FIXME: Is that correct? */ - {}, locus) - {} + Visibility vis, location_t locus); - ExternalTypeItem (ExternalTypeItem const &other) : ExternalItem (other) {} + ExternalTypeItem (ExternalTypeItem const &other); ExternalTypeItem (ExternalTypeItem &&other) = default; ExternalTypeItem &operator= (ExternalTypeItem &&other) = default; @@ -3201,36 +2628,13 @@ public: ExternBlock (Analysis::NodeMapping mappings, ABI abi, std::vector<std::unique_ptr<ExternalItem>> extern_items, Visibility vis, AST::AttrVec inner_attrs, - AST::AttrVec outer_attrs, location_t locus) - : VisItem (std::move (mappings), std::move (vis), std::move (outer_attrs)), - WithInnerAttrs (std::move (inner_attrs)), abi (abi), - extern_items (std::move (extern_items)), locus (locus) - {} + AST::AttrVec outer_attrs, location_t locus); // Copy constructor with vector clone - ExternBlock (ExternBlock const &other) - : VisItem (other), WithInnerAttrs (other.inner_attrs), abi (other.abi), - locus (other.locus) - { - extern_items.reserve (other.extern_items.size ()); - for (const auto &e : other.extern_items) - extern_items.push_back (e->clone_external_item ()); - } + ExternBlock (ExternBlock const &other); // Overloaded assignment operator with vector clone - ExternBlock &operator= (ExternBlock const &other) - { - VisItem::operator= (other); - abi = other.abi; - inner_attrs = other.inner_attrs; - locus = other.locus; - - extern_items.reserve (other.extern_items.size ()); - for (const auto &e : other.extern_items) - extern_items.push_back (e->clone_external_item ()); - - return *this; - } + ExternBlock &operator= (ExternBlock const &other); // move constructors ExternBlock (ExternBlock &&other) = default; diff --git a/gcc/rust/hir/tree/rust-hir-literal.h b/gcc/rust/hir/tree/rust-hir-literal.h new file mode 100644 index 0000000..9a97e71 --- /dev/null +++ b/gcc/rust/hir/tree/rust-hir-literal.h @@ -0,0 +1,78 @@ +// Copyright (C) 2020-2024 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_HIR_LITERAL_H +#define RUST_HIR_LITERAL_H + +#include "rust-token.h" + +namespace Rust { +namespace HIR { +// A literal - value with a type. Used in LiteralExpr and LiteralPattern. +struct Literal +{ +public: + enum LitType + { + CHAR, + STRING, + BYTE, + BYTE_STRING, + INT, + FLOAT, + BOOL + }; + +private: + std::string value_as_string; + LitType type; + PrimitiveCoreType type_hint; + +public: + std::string as_string () const { return value_as_string; } + + LitType get_lit_type () const { return type; } + + PrimitiveCoreType get_type_hint () const { return type_hint; } + + Literal (std::string value_as_string, LitType type, + PrimitiveCoreType type_hint) + : value_as_string (std::move (value_as_string)), type (type), + type_hint (type_hint) + {} + + static Literal create_error () + { + return Literal ("", CHAR, PrimitiveCoreType::CORETYPE_UNKNOWN); + } + + void set_lit_type (LitType lt) { type = lt; } + + // Returns whether literal is in an invalid state. + bool is_error () const { return value_as_string == ""; } + + bool is_equal (Literal &other) + { + return value_as_string == other.value_as_string && type == other.type + && type_hint == other.type_hint; + } +}; +} // namespace HIR +} // namespace Rust + +#endif diff --git a/gcc/rust/hir/tree/rust-hir-node.h b/gcc/rust/hir/tree/rust-hir-node.h new file mode 100644 index 0000000..4010c23 --- /dev/null +++ b/gcc/rust/hir/tree/rust-hir-node.h @@ -0,0 +1,63 @@ +// Copyright (C) 2020-2024 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_HIR_NODE_H +#define RUST_HIR_NODE_H + +namespace Rust { + +namespace HIR { + +class Node +{ +public: + // Kind for downcasting various HIR nodes to other base classes when visiting + // them + enum BaseKind + { + /* class ExternalItem */ + EXTERNAL, + /* class TraitItem */ + TRAIT_ITEM, + /* class VisItem */ + VIS_ITEM, + /* class Item */ + ITEM, + /* class ImplItem */ + IMPL, + /* class Type */ + TYPE, + /* class Stmt */ + STMT, + /* class Expr */ + EXPR, + /* class Pattern */ + PATTERN, + }; + + /** + * Get the kind of HIR node we are dealing with. This is useful for + * downcasting to more precise types when necessary, i.e going from an `Item*` + * to a `VisItem*` + */ + virtual BaseKind get_hir_kind () = 0; +}; + +} // namespace HIR +} // namespace Rust +#endif diff --git a/gcc/rust/hir/tree/rust-hir-path.cc b/gcc/rust/hir/tree/rust-hir-path.cc new file mode 100644 index 0000000..ee4a572 --- /dev/null +++ b/gcc/rust/hir/tree/rust-hir-path.cc @@ -0,0 +1,420 @@ +// Copyright (C) 2020-2024 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-hir-path.h" +#include "optional.h" +#include "rust-hir-bound.h" + +namespace Rust { +namespace HIR { + +GenericArgsBinding::GenericArgsBinding (Identifier ident, + std::unique_ptr<Type> type_ptr, + location_t locus) + : identifier (std::move (ident)), type (std::move (type_ptr)), locus (locus) +{} + +GenericArgsBinding::GenericArgsBinding (GenericArgsBinding const &other) + : identifier (other.identifier), type (other.type->clone_type ()), + locus (other.locus) +{} + +GenericArgsBinding & +GenericArgsBinding::operator= (GenericArgsBinding const &other) +{ + identifier = other.identifier; + type = other.type->clone_type (); + locus = other.locus; + return *this; +} + +ConstGenericArg::ConstGenericArg (std::unique_ptr<Expr> expression, + location_t locus) + : expression (std::move (expression)), locus (locus) +{} + +ConstGenericArg::ConstGenericArg (const ConstGenericArg &other) + : locus (other.locus) +{ + expression = other.expression->clone_expr (); +} + +ConstGenericArg +ConstGenericArg::operator= (const ConstGenericArg &other) +{ + expression = other.expression->clone_expr (); + locus = other.locus; + + return *this; +} + +GenericArgs & +GenericArgs::operator= (GenericArgs const &other) +{ + lifetime_args = other.lifetime_args; + binding_args = other.binding_args; + const_args = other.const_args; + locus = other.locus; + + type_args.clear (); + type_args.reserve (other.type_args.size ()); + for (const auto &e : other.type_args) + type_args.push_back (e->clone_type ()); + + return *this; +} + +GenericArgs::GenericArgs (std::vector<Lifetime> lifetime_args, + std::vector<std::unique_ptr<Type> > type_args, + std::vector<GenericArgsBinding> binding_args, + std::vector<ConstGenericArg> const_args, + location_t locus) + : lifetime_args (std::move (lifetime_args)), + type_args (std::move (type_args)), binding_args (std::move (binding_args)), + const_args (std::move (const_args)), locus (locus) +{} + +GenericArgs::GenericArgs (GenericArgs const &other) + : lifetime_args (other.lifetime_args), binding_args (other.binding_args), + const_args (other.const_args), locus (other.locus) +{ + type_args.clear (); + type_args.reserve (other.type_args.size ()); + + for (const auto &e : other.type_args) + type_args.push_back (e->clone_type ()); +} + +bool +GenericArgs::is_empty () const +{ + return lifetime_args.size () == 0 && type_args.size () == 0 + && binding_args.size () == 0; +} + +PathExprSegment::PathExprSegment (Analysis::NodeMapping mappings, + PathIdentSegment segment_name, + location_t locus, GenericArgs generic_args) + : mappings (std::move (mappings)), segment_name (std::move (segment_name)), + generic_args (std::move (generic_args)), locus (locus) +{} + +PathExprSegment::PathExprSegment (PathExprSegment const &other) + : mappings (other.mappings), segment_name (other.segment_name), + generic_args (other.generic_args), locus (other.locus) +{} + +PathExprSegment & +PathExprSegment::operator= (PathExprSegment const &other) +{ + mappings = other.mappings; + segment_name = other.segment_name; + generic_args = other.generic_args; + locus = other.locus; + + return *this; +} + +void +PathPattern::iterate_path_segments (std::function<bool (PathExprSegment &)> cb) +{ + rust_assert (kind == Kind::Segmented); + + for (auto it = segments.begin (); it != segments.end (); it++) + { + if (!cb (*it)) + return; + } +} + +PathInExpression::PathInExpression (Analysis::NodeMapping mappings, + std::vector<PathExprSegment> path_segments, + location_t locus, + bool has_opening_scope_resolution, + std::vector<AST::Attribute> outer_attrs) + : PathPattern (std::move (path_segments)), + PathExpr (std::move (mappings), std::move (outer_attrs)), + has_opening_scope_resolution (has_opening_scope_resolution), locus (locus) +{} + +PathInExpression::PathInExpression (Analysis::NodeMapping mappings, + LangItem::Kind lang_item, location_t locus, + bool has_opening_scope_resolution, + std::vector<AST::Attribute> outer_attrs) + : PathPattern (lang_item), + PathExpr (std::move (mappings), std::move (outer_attrs)), + has_opening_scope_resolution (has_opening_scope_resolution), locus (locus) +{} + +bool +PathInExpression::is_self () const + +{ + if (!is_single_segment ()) + return false; + + return get_final_segment ().get_segment ().as_string ().compare ("self") == 0; +} + +TypePathSegment::TypePathSegment (Analysis::NodeMapping mappings, + PathIdentSegment ident_segment, + bool has_separating_scope_resolution, + location_t locus) + : mappings (std::move (mappings)), ident_segment (std::move (ident_segment)), + lang_item (tl::nullopt), locus (locus), + has_separating_scope_resolution (has_separating_scope_resolution), + type (SegmentType::REG) +{} + +TypePathSegment::TypePathSegment (Analysis::NodeMapping mappings, + LangItem::Kind lang_item, location_t locus) + : mappings (std::move (mappings)), ident_segment (tl::nullopt), + lang_item (lang_item), locus (locus), + has_separating_scope_resolution (false), type (SegmentType::REG) +{} + +TypePathSegment::TypePathSegment (Analysis::NodeMapping mappings, + std::string segment_name, + bool has_separating_scope_resolution, + location_t locus) + : mappings (std::move (mappings)), + ident_segment (PathIdentSegment (std::move (segment_name))), + lang_item (tl::nullopt), locus (locus), + has_separating_scope_resolution (has_separating_scope_resolution), + type (SegmentType::REG) +{} + +TypePathSegmentGeneric::TypePathSegmentGeneric ( + Analysis::NodeMapping mappings, PathIdentSegment ident_segment, + bool has_separating_scope_resolution, GenericArgs generic_args, + location_t locus) + : TypePathSegment (std::move (mappings), std::move (ident_segment), + has_separating_scope_resolution, locus), + generic_args (std::move (generic_args)) +{} + +TypePathSegmentGeneric::TypePathSegmentGeneric (Analysis::NodeMapping mappings, + LangItem::Kind lang_item, + GenericArgs generic_args, + location_t locus) + : TypePathSegment (std::move (mappings), lang_item, locus), + generic_args (std::move (generic_args)) +{} + +TypePathSegmentGeneric::TypePathSegmentGeneric ( + Analysis::NodeMapping mappings, std::string segment_name, + bool has_separating_scope_resolution, std::vector<Lifetime> lifetime_args, + std::vector<std::unique_ptr<Type> > type_args, + std::vector<GenericArgsBinding> binding_args, + std::vector<ConstGenericArg> const_args, location_t locus) + : TypePathSegment (std::move (mappings), std::move (segment_name), + has_separating_scope_resolution, locus), + generic_args (GenericArgs (std::move (lifetime_args), std::move (type_args), + std::move (binding_args), std::move (const_args), + locus)) +{} + +TypePathFunction::TypePathFunction (std::vector<std::unique_ptr<Type> > inputs, + std::unique_ptr<Type> type) + : inputs (std::move (inputs)), return_type (std::move (type)) +{} + +TypePathFunction::TypePathFunction (TypePathFunction const &other) +{ + return_type = other.has_return_type () + ? other.get_return_type ().clone_type () + : nullptr; + + inputs.reserve (other.inputs.size ()); + for (const auto &e : other.inputs) + inputs.push_back (e->clone_type ()); +} + +TypePathFunction & +TypePathFunction::operator= (TypePathFunction const &other) +{ + return_type = other.has_return_type () + ? other.get_return_type ().clone_type () + : nullptr; + + inputs.reserve (other.inputs.size ()); + for (const auto &e : other.inputs) + inputs.push_back (e->clone_type ()); + + return *this; +} + +TypePathSegmentFunction::TypePathSegmentFunction ( + Analysis::NodeMapping mappings, PathIdentSegment ident_segment, + bool has_separating_scope_resolution, TypePathFunction function_path, + location_t locus) + : TypePathSegment (std::move (mappings), std::move (ident_segment), + has_separating_scope_resolution, locus), + function_path (std::move (function_path)) +{} + +TypePathSegmentFunction::TypePathSegmentFunction ( + Analysis::NodeMapping mappings, std::string segment_name, + bool has_separating_scope_resolution, TypePathFunction function_path, + location_t locus) + : TypePathSegment (std::move (mappings), std::move (segment_name), + has_separating_scope_resolution, locus), + function_path (std::move (function_path)) +{} + +TypePath::TypePath (Analysis::NodeMapping mappings, + std::vector<std::unique_ptr<TypePathSegment> > segments, + location_t locus, bool has_opening_scope_resolution) + : TypeNoBounds (mappings, locus), + has_opening_scope_resolution (has_opening_scope_resolution), + segments (std::move (segments)) +{} + +TypePath::TypePath (TypePath const &other) + : TypeNoBounds (other.mappings, other.locus), + has_opening_scope_resolution (other.has_opening_scope_resolution) +{ + segments.reserve (other.segments.size ()); + for (const auto &e : other.segments) + segments.push_back (e->clone_type_path_segment ()); +} + +TypePath & +TypePath::operator= (TypePath const &other) +{ + has_opening_scope_resolution = other.has_opening_scope_resolution; + locus = other.locus; + mappings = other.mappings; + + segments.reserve (other.segments.size ()); + for (const auto &e : other.segments) + segments.push_back (e->clone_type_path_segment ()); + + return *this; +} + +QualifiedPathType::QualifiedPathType (Analysis::NodeMapping mappings, + std::unique_ptr<Type> type, + std::unique_ptr<TypePath> trait, + location_t locus) + : type (std::move (type)), trait (std::move (trait)), locus (locus), + mappings (mappings) +{} + +QualifiedPathType::QualifiedPathType (QualifiedPathType const &other) + : type (other.type->clone_type ()), + trait (other.has_as_clause () + ? std::unique_ptr<HIR::TypePath> (new HIR::TypePath (*other.trait)) + : nullptr), + locus (other.locus), mappings (other.mappings) +{} + +QualifiedPathType & +QualifiedPathType::operator= (QualifiedPathType const &other) +{ + type = other.type->clone_type (); + locus = other.locus; + mappings = other.mappings; + trait = other.has_as_clause () + ? std::unique_ptr<HIR::TypePath> (new HIR::TypePath (*other.trait)) + : nullptr; + + return *this; +} + +bool +QualifiedPathType::trait_has_generic_args () const +{ + rust_assert (has_as_clause ()); + bool is_generic_seg = trait->get_final_segment ().get_type () + == TypePathSegment::SegmentType::GENERIC; + if (!is_generic_seg) + return false; + + auto &seg + = static_cast<TypePathSegmentGeneric &> (trait->get_final_segment ()); + return seg.has_generic_args (); +} + +GenericArgs & +QualifiedPathType::get_trait_generic_args () +{ + rust_assert (trait_has_generic_args ()); + auto &seg + = static_cast<TypePathSegmentGeneric &> (trait->get_final_segment ()); + return seg.get_generic_args (); +} + +QualifiedPathInExpression::QualifiedPathInExpression ( + Analysis::NodeMapping mappings, QualifiedPathType qual_path_type, + std::vector<PathExprSegment> path_segments, location_t locus, + std::vector<AST::Attribute> outer_attrs) + : PathPattern (std::move (path_segments)), + PathExpr (std::move (mappings), std::move (outer_attrs)), + path_type (std::move (qual_path_type)), locus (locus) +{} + +QualifiedPathInExpression::QualifiedPathInExpression ( + Analysis::NodeMapping mappings, QualifiedPathType qual_path_type, + LangItem::Kind lang_item, location_t locus, + std::vector<AST::Attribute> outer_attrs) + : PathPattern (lang_item), + PathExpr (std::move (mappings), std::move (outer_attrs)), + path_type (std::move (qual_path_type)), locus (locus) +{} + +QualifiedPathInType::QualifiedPathInType ( + Analysis::NodeMapping mappings, QualifiedPathType qual_path_type, + std::unique_ptr<TypePathSegment> associated_segment, + std::vector<std::unique_ptr<TypePathSegment> > path_segments, + location_t locus) + : TypeNoBounds (mappings, locus), path_type (std::move (qual_path_type)), + associated_segment (std::move (associated_segment)), + segments (std::move (path_segments)) +{} + +QualifiedPathInType::QualifiedPathInType (QualifiedPathInType const &other) + : TypeNoBounds (other.mappings, other.locus), path_type (other.path_type) +{ + auto seg = other.associated_segment->clone_type_path_segment_impl (); + associated_segment = std::unique_ptr<TypePathSegment> (seg); + + segments.reserve (other.segments.size ()); + for (const auto &e : other.segments) + segments.push_back (e->clone_type_path_segment ()); +} + +QualifiedPathInType & +QualifiedPathInType::operator= (QualifiedPathInType const &other) +{ + auto seg = other.associated_segment->clone_type_path_segment_impl (); + associated_segment = std::unique_ptr<TypePathSegment> (seg); + + path_type = other.path_type; + locus = other.locus; + mappings = other.mappings; + + segments.reserve (other.segments.size ()); + for (const auto &e : other.segments) + segments.push_back (e->clone_type_path_segment ()); + + return *this; +} + +} // namespace HIR +} // namespace Rust diff --git a/gcc/rust/hir/tree/rust-hir-path.h b/gcc/rust/hir/tree/rust-hir-path.h index e406d53..3ce2662 100644 --- a/gcc/rust/hir/tree/rust-hir-path.h +++ b/gcc/rust/hir/tree/rust-hir-path.h @@ -19,7 +19,11 @@ #ifndef RUST_HIR_PATH_H #define RUST_HIR_PATH_H -#include "rust-hir.h" +#include "rust-hir-map.h" +#include "rust-hir-simple-path.h" +#include "rust-hir-type-no-bounds.h" +#include "rust-hir-pattern-abstract.h" +#include "rust-hir-expr-abstract.h" namespace Rust { namespace HIR { @@ -76,27 +80,16 @@ public: // Pointer type for type in constructor to enable polymorphism GenericArgsBinding (Identifier ident, std::unique_ptr<Type> type_ptr, - location_t locus = UNDEF_LOCATION) - : identifier (std::move (ident)), type (std::move (type_ptr)), locus (locus) - {} + location_t locus = UNDEF_LOCATION); // Copy constructor has to deep copy the type as it is a unique pointer - GenericArgsBinding (GenericArgsBinding const &other) - : identifier (other.identifier), type (other.type->clone_type ()), - locus (other.locus) - {} + GenericArgsBinding (GenericArgsBinding const &other); // default destructor ~GenericArgsBinding () = default; // Overload assignment operator to deep copy the pointed-to type - GenericArgsBinding &operator= (GenericArgsBinding const &other) - { - identifier = other.identifier; - type = other.type->clone_type (); - locus = other.locus; - return *this; - } + GenericArgsBinding &operator= (GenericArgsBinding const &other); // move constructors GenericArgsBinding (GenericArgsBinding &&other) = default; @@ -107,8 +100,16 @@ public: Identifier &get_identifier () { return identifier; } const Identifier &get_identifier () const { return identifier; } - std::unique_ptr<Type> &get_type () { return type; } - const std::unique_ptr<Type> &get_type () const { return type; } + Type &get_type () + { + rust_assert (type); + return *type; + } + const Type &get_type () const + { + rust_assert (type); + return *type; + } location_t get_locus () const { return locus; } }; @@ -119,22 +120,11 @@ class ConstGenericArg // at name-resolution, hence no need for ambiguities here public: - ConstGenericArg (std::unique_ptr<Expr> expression, location_t locus) - : expression (std::move (expression)), locus (locus) - {} - - ConstGenericArg (const ConstGenericArg &other) : locus (other.locus) - { - expression = other.expression->clone_expr (); - } + ConstGenericArg (std::unique_ptr<Expr> expression, location_t locus); - ConstGenericArg operator= (const ConstGenericArg &other) - { - expression = other.expression->clone_expr (); - locus = other.locus; + ConstGenericArg (const ConstGenericArg &other); - return *this; - } + ConstGenericArg operator= (const ConstGenericArg &other); std::unique_ptr<Expr> &get_expression () { return expression; } @@ -162,42 +152,15 @@ public: GenericArgs (std::vector<Lifetime> lifetime_args, std::vector<std::unique_ptr<Type> > type_args, std::vector<GenericArgsBinding> binding_args, - std::vector<ConstGenericArg> const_args, location_t locus) - : lifetime_args (std::move (lifetime_args)), - type_args (std::move (type_args)), - binding_args (std::move (binding_args)), - const_args (std::move (const_args)), locus (locus) - {} + std::vector<ConstGenericArg> const_args, location_t locus); // copy constructor with vector clone - GenericArgs (GenericArgs const &other) - : lifetime_args (other.lifetime_args), binding_args (other.binding_args), - const_args (other.const_args), locus (other.locus) - { - type_args.clear (); - type_args.reserve (other.type_args.size ()); - - for (const auto &e : other.type_args) - type_args.push_back (e->clone_type ()); - } + GenericArgs (GenericArgs const &other); ~GenericArgs () = default; // overloaded assignment operator to vector clone - GenericArgs &operator= (GenericArgs const &other) - { - lifetime_args = other.lifetime_args; - binding_args = other.binding_args; - const_args = other.const_args; - locus = other.locus; - - type_args.clear (); - type_args.reserve (other.type_args.size ()); - for (const auto &e : other.type_args) - type_args.push_back (e->clone_type ()); - - return *this; - } + GenericArgs &operator= (GenericArgs const &other); // move constructors GenericArgs (GenericArgs &&other) = default; @@ -209,11 +172,7 @@ public: return GenericArgs ({}, {}, {}, {}, locus); } - bool is_empty () const - { - return lifetime_args.size () == 0 && type_args.size () == 0 - && binding_args.size () == 0; - } + bool is_empty () const; std::string as_string () const; @@ -245,25 +204,11 @@ private: public: PathExprSegment (Analysis::NodeMapping mappings, PathIdentSegment segment_name, location_t locus, - GenericArgs generic_args) - : mappings (std::move (mappings)), segment_name (std::move (segment_name)), - generic_args (std::move (generic_args)), locus (locus) - {} + GenericArgs generic_args); - PathExprSegment (PathExprSegment const &other) - : mappings (other.mappings), segment_name (other.segment_name), - generic_args (other.generic_args), locus (other.locus) - {} + PathExprSegment (PathExprSegment const &other); - PathExprSegment &operator= (PathExprSegment const &other) - { - mappings = other.mappings; - segment_name = other.segment_name; - generic_args = other.generic_args; - locus = other.locus; - - return *this; - } + PathExprSegment &operator= (PathExprSegment const &other); // move constructors PathExprSegment (PathExprSegment &&other) = default; @@ -286,15 +231,34 @@ public: // HIR node representing a pattern that involves a "path" - abstract base class class PathPattern : public Pattern { +public: + enum class Kind + { + Segmented, + LangItem + }; + +private: std::vector<PathExprSegment> segments; + tl::optional<LangItem::Kind> lang_item; + Kind kind; protected: PathPattern (std::vector<PathExprSegment> segments) - : segments (std::move (segments)) + : segments (std::move (segments)), lang_item (tl::nullopt), + kind (Kind::Segmented) + {} + + PathPattern (LangItem::Kind lang_item) + : segments ({}), lang_item (lang_item), kind (Kind::LangItem) {} // Returns whether path has segments. - bool has_segments () const { return !segments.empty (); } + bool has_segments () const + { + rust_assert (kind == Kind::Segmented); + return !segments.empty (); + } /* Converts path segments to their equivalent SimplePath segments if possible, * and creates a SimplePath from them. */ @@ -304,33 +268,61 @@ protected: public: /* Returns whether the path is a single segment (excluding qualified path * initial as segment). */ - bool is_single_segment () const { return segments.size () == 1; } + bool is_single_segment () const + { + rust_assert (kind == Kind::Segmented); + return segments.size () == 1; + } std::string as_string () const override; - void iterate_path_segments (std::function<bool (PathExprSegment &)> cb) + void iterate_path_segments (std::function<bool (PathExprSegment &)> cb); + + size_t get_num_segments () const { - for (auto it = segments.begin (); it != segments.end (); it++) - { - if (!cb (*it)) - return; - } + rust_assert (kind == Kind::Segmented); + return segments.size (); } - size_t get_num_segments () const { return segments.size (); } + std::vector<PathExprSegment> &get_segments () + { + rust_assert (kind == Kind::Segmented); + return segments; + } + + const std::vector<PathExprSegment> &get_segments () const + { + rust_assert (kind == Kind::Segmented); + return segments; + } - std::vector<PathExprSegment> &get_segments () { return segments; } + PathExprSegment &get_root_seg () + { + rust_assert (kind == Kind::Segmented); + return segments.at (0); + } - const std::vector<PathExprSegment> &get_segments () const { return segments; } + const PathExprSegment &get_final_segment () const + { + rust_assert (kind == Kind::Segmented); + return segments.back (); + } - PathExprSegment &get_root_seg () { return segments.at (0); } + LangItem::Kind get_lang_item () const + { + rust_assert (kind == Kind::LangItem); - const PathExprSegment &get_final_segment () const { return segments.back (); } + return *lang_item; + } PatternType get_pattern_type () const override final { return PatternType::PATH; } + + bool is_lang_item () const { return kind == Kind::LangItem; } + + Kind get_path_kind () const { return kind; } }; /* HIR node representing a path-in-expression pattern (path that allows generic @@ -349,11 +341,14 @@ public: location_t locus = UNDEF_LOCATION, bool has_opening_scope_resolution = false, std::vector<AST::Attribute> outer_attrs - = std::vector<AST::Attribute> ()) - : PathPattern (std::move (path_segments)), - PathExpr (std::move (mappings), std::move (outer_attrs)), - has_opening_scope_resolution (has_opening_scope_resolution), locus (locus) - {} + = std::vector<AST::Attribute> ()); + + // lang-item Constructor + PathInExpression (Analysis::NodeMapping mappings, LangItem::Kind kind, + location_t locus = UNDEF_LOCATION, + bool has_opening_scope_resolution = false, + std::vector<AST::Attribute> outer_attrs + = std::vector<AST::Attribute> ()); // Creates an error state path in expression. static PathInExpression create_error () @@ -385,14 +380,7 @@ public: bool opening_scope_resolution () { return has_opening_scope_resolution; } - bool is_self () const - { - if (!is_single_segment ()) - return false; - - return get_final_segment ().get_segment ().as_string ().compare ("self") - == 0; - } + bool is_self () const; const Analysis::NodeMapping &get_mappings () const override final { @@ -429,7 +417,8 @@ public: private: Analysis::NodeMapping mappings; - PathIdentSegment ident_segment; + tl::optional<PathIdentSegment> ident_segment; + tl::optional<LangItem::Kind> lang_item; location_t locus; protected: @@ -456,27 +445,29 @@ public: TypePathSegment (Analysis::NodeMapping mappings, PathIdentSegment ident_segment, - bool has_separating_scope_resolution, location_t locus) - : mappings (std::move (mappings)), - ident_segment (std::move (ident_segment)), locus (locus), - has_separating_scope_resolution (has_separating_scope_resolution), - type (SegmentType::REG) - {} + bool has_separating_scope_resolution, location_t locus); + + TypePathSegment (Analysis::NodeMapping mappings, LangItem::Kind lang_item, + location_t locus); TypePathSegment (Analysis::NodeMapping mappings, std::string segment_name, - bool has_separating_scope_resolution, location_t locus) - : mappings (std::move (mappings)), - ident_segment (PathIdentSegment (std::move (segment_name))), - locus (locus), - has_separating_scope_resolution (has_separating_scope_resolution), - type (SegmentType::REG) - {} + bool has_separating_scope_resolution, location_t locus); - virtual std::string as_string () const { return ident_segment.as_string (); } + virtual std::string as_string () const + { + if (ident_segment) + return ident_segment->as_string (); + + return LangItem::PrettyString (*lang_item); + } /* Returns whether the type path segment is in an error state. May be virtual * in future. */ - bool is_error () const { return ident_segment.is_error (); } + bool is_error () const + { + rust_assert (ident_segment); + return ident_segment->is_error (); + } /* Returns whether segment is identifier only (as opposed to generic args or * function). Overriden in derived classes with other segments. */ @@ -489,12 +480,24 @@ public: const Analysis::NodeMapping &get_mappings () const { return mappings; } - const PathIdentSegment &get_ident_segment () const { return ident_segment; } + const PathIdentSegment &get_ident_segment () const + { + rust_assert (ident_segment); + return *ident_segment; + } + + const LangItem::Kind &get_lang_item () const + { + rust_assert (lang_item); + return *lang_item; + } bool is_generic_segment () const { return get_type () == SegmentType::GENERIC; } + + bool is_lang_item () const { return lang_item.has_value (); } }; // Segment used in type path with generic args @@ -511,11 +514,11 @@ public: TypePathSegmentGeneric (Analysis::NodeMapping mappings, PathIdentSegment ident_segment, bool has_separating_scope_resolution, - GenericArgs generic_args, location_t locus) - : TypePathSegment (std::move (mappings), std::move (ident_segment), - has_separating_scope_resolution, locus), - generic_args (std::move (generic_args)) - {} + GenericArgs generic_args, location_t locus); + + TypePathSegmentGeneric (Analysis::NodeMapping mappings, + LangItem::Kind lang_item, GenericArgs generic_args, + location_t locus); // Constructor from segment name and all args TypePathSegmentGeneric (Analysis::NodeMapping mappings, @@ -525,13 +528,7 @@ public: std::vector<std::unique_ptr<Type> > type_args, std::vector<GenericArgsBinding> binding_args, std::vector<ConstGenericArg> const_args, - location_t locus) - : TypePathSegment (std::move (mappings), std::move (segment_name), - has_separating_scope_resolution, locus), - generic_args ( - GenericArgs (std::move (lifetime_args), std::move (type_args), - std::move (binding_args), std::move (const_args), locus)) - {} + location_t locus); std::string as_string () const override; @@ -566,37 +563,15 @@ public: // Constructor TypePathFunction (std::vector<std::unique_ptr<Type> > inputs, - std::unique_ptr<Type> type) - : inputs (std::move (inputs)), return_type (std::move (type)) - {} + std::unique_ptr<Type> type); // Copy constructor with clone - TypePathFunction (TypePathFunction const &other) - { - return_type = other.has_return_type () - ? other.get_return_type ()->clone_type () - : nullptr; - - inputs.reserve (other.inputs.size ()); - for (const auto &e : other.inputs) - inputs.push_back (e->clone_type ()); - } + TypePathFunction (TypePathFunction const &other); ~TypePathFunction () = default; // Overloaded assignment operator to clone type - TypePathFunction &operator= (TypePathFunction const &other) - { - return_type = other.has_return_type () - ? other.get_return_type ()->clone_type () - : nullptr; - - inputs.reserve (other.inputs.size ()); - for (const auto &e : other.inputs) - inputs.push_back (e->clone_type ()); - - return *this; - } + TypePathFunction &operator= (TypePathFunction const &other); // move constructors TypePathFunction (TypePathFunction &&other) = default; @@ -610,8 +585,8 @@ public: }; std::vector<std::unique_ptr<Type> > &get_params () { return inputs; }; - const std::unique_ptr<Type> &get_return_type () const { return return_type; }; - std::unique_ptr<Type> &get_return_type () { return return_type; }; + const Type &get_return_type () const { return *return_type; }; + Type &get_return_type () { return *return_type; }; }; // Segment used in type path with a function argument @@ -624,21 +599,13 @@ public: TypePathSegmentFunction (Analysis::NodeMapping mappings, PathIdentSegment ident_segment, bool has_separating_scope_resolution, - TypePathFunction function_path, location_t locus) - : TypePathSegment (std::move (mappings), std::move (ident_segment), - has_separating_scope_resolution, locus), - function_path (std::move (function_path)) - {} + TypePathFunction function_path, location_t locus); // Constructor with segment name and TypePathFn TypePathSegmentFunction (Analysis::NodeMapping mappings, std::string segment_name, bool has_separating_scope_resolution, - TypePathFunction function_path, location_t locus) - : TypePathSegment (std::move (mappings), std::move (segment_name), - has_separating_scope_resolution, locus), - function_path (std::move (function_path)) - {} + TypePathFunction function_path, location_t locus); std::string as_string () const override; @@ -698,35 +665,13 @@ public: // Constructor TypePath (Analysis::NodeMapping mappings, std::vector<std::unique_ptr<TypePathSegment> > segments, - location_t locus, bool has_opening_scope_resolution = false) - : TypeNoBounds (mappings, locus), - has_opening_scope_resolution (has_opening_scope_resolution), - segments (std::move (segments)) - {} + location_t locus, bool has_opening_scope_resolution = false); // Copy constructor with vector clone - TypePath (TypePath const &other) - : TypeNoBounds (other.mappings, other.locus), - has_opening_scope_resolution (other.has_opening_scope_resolution) - { - segments.reserve (other.segments.size ()); - for (const auto &e : other.segments) - segments.push_back (e->clone_type_path_segment ()); - } + TypePath (TypePath const &other); // Overloaded assignment operator with clone - TypePath &operator= (TypePath const &other) - { - has_opening_scope_resolution = other.has_opening_scope_resolution; - locus = other.locus; - mappings = other.mappings; - - segments.reserve (other.segments.size ()); - for (const auto &e : other.segments) - segments.push_back (e->clone_type_path_segment ()); - - return *this; - } + TypePath &operator= (TypePath const &other); // move constructors TypePath (TypePath &&other) = default; @@ -739,7 +684,7 @@ public: AST::SimplePath as_simple_path () const; // Creates a trait bound with a clone of this type path as its only element. - TraitBound *to_trait_bound (bool in_parens) const override; + std::unique_ptr<TraitBound> to_trait_bound (bool in_parens) const override; void accept_vis (HIRFullVisitor &vis) override; void accept_vis (HIRTypeVisitor &vis) override; @@ -751,10 +696,7 @@ public: return segments; } - std::unique_ptr<TypePathSegment> &get_final_segment () - { - return segments.back (); - } + TypePathSegment &get_final_segment () { return *segments.back (); } }; class QualifiedPathType @@ -767,36 +709,16 @@ class QualifiedPathType public: // Constructor QualifiedPathType (Analysis::NodeMapping mappings, std::unique_ptr<Type> type, - std::unique_ptr<TypePath> trait, location_t locus) - : type (std::move (type)), trait (std::move (trait)), locus (locus), - mappings (mappings) - {} + std::unique_ptr<TypePath> trait, location_t locus); // Copy constructor uses custom deep copy for Type to preserve polymorphism - QualifiedPathType (QualifiedPathType const &other) - : type (other.type->clone_type ()), - trait (other.has_as_clause () ? std::unique_ptr<HIR::TypePath> ( - new HIR::TypePath (*other.trait)) - : nullptr), - locus (other.locus), mappings (other.mappings) - {} + QualifiedPathType (QualifiedPathType const &other); // default destructor ~QualifiedPathType () = default; // overload assignment operator to use custom clone method - QualifiedPathType &operator= (QualifiedPathType const &other) - { - type = other.type->clone_type (); - locus = other.locus; - mappings = other.mappings; - trait - = other.has_as_clause () - ? std::unique_ptr<HIR::TypePath> (new HIR::TypePath (*other.trait)) - : nullptr; - - return *this; - } + QualifiedPathType &operator= (QualifiedPathType const &other); // move constructor QualifiedPathType (QualifiedPathType &&other) = default; @@ -811,30 +733,24 @@ public: Analysis::NodeMapping get_mappings () const { return mappings; } - std::unique_ptr<Type> &get_type () { return type; } - - std::unique_ptr<TypePath> &get_trait () { return trait; } + bool has_type () { return type != nullptr; } + bool has_trait () { return trait != nullptr; } - bool trait_has_generic_args () const + Type &get_type () { - rust_assert (has_as_clause ()); - bool is_generic_seg = trait->get_final_segment ()->get_type () - == TypePathSegment::SegmentType::GENERIC; - if (!is_generic_seg) - return false; - - TypePathSegmentGeneric *seg = static_cast<TypePathSegmentGeneric *> ( - trait->get_final_segment ().get ()); - return seg->has_generic_args (); + rust_assert (type); + return *type; } - GenericArgs &get_trait_generic_args () + TypePath &get_trait () { - rust_assert (trait_has_generic_args ()); - TypePathSegmentGeneric *seg = static_cast<TypePathSegmentGeneric *> ( - trait->get_final_segment ().get ()); - return seg->get_generic_args (); + rust_assert (trait); + return *trait; } + + bool trait_has_generic_args () const; + + GenericArgs &get_trait_generic_args (); }; /* HIR node representing a qualified path-in-expression pattern (path that @@ -852,11 +768,15 @@ public: std::vector<PathExprSegment> path_segments, location_t locus = UNDEF_LOCATION, std::vector<AST::Attribute> outer_attrs - = std::vector<AST::Attribute> ()) - : PathPattern (std::move (path_segments)), - PathExpr (std::move (mappings), std::move (outer_attrs)), - path_type (std::move (qual_path_type)), locus (locus) - {} + = std::vector<AST::Attribute> ()); + + // lang-item constructor + QualifiedPathInExpression (Analysis::NodeMapping mappings, + QualifiedPathType qual_path_type, + LangItem::Kind lang_item, + location_t locus = UNDEF_LOCATION, + std::vector<AST::Attribute> outer_attrs + = std::vector<AST::Attribute> ()); location_t get_locus () const override final { return locus; } @@ -917,40 +837,13 @@ public: Analysis::NodeMapping mappings, QualifiedPathType qual_path_type, std::unique_ptr<TypePathSegment> associated_segment, std::vector<std::unique_ptr<TypePathSegment> > path_segments, - location_t locus = UNDEF_LOCATION) - : TypeNoBounds (mappings, locus), path_type (std::move (qual_path_type)), - associated_segment (std::move (associated_segment)), - segments (std::move (path_segments)) - {} + location_t locus = UNDEF_LOCATION); // Copy constructor with vector clone - QualifiedPathInType (QualifiedPathInType const &other) - : TypeNoBounds (other.mappings, other.locus), path_type (other.path_type) - { - auto seg = other.associated_segment->clone_type_path_segment_impl (); - associated_segment = std::unique_ptr<TypePathSegment> (seg); - - segments.reserve (other.segments.size ()); - for (const auto &e : other.segments) - segments.push_back (e->clone_type_path_segment ()); - } + QualifiedPathInType (QualifiedPathInType const &other); // Overloaded assignment operator with vector clone - QualifiedPathInType &operator= (QualifiedPathInType const &other) - { - auto seg = other.associated_segment->clone_type_path_segment_impl (); - associated_segment = std::unique_ptr<TypePathSegment> (seg); - - path_type = other.path_type; - locus = other.locus; - mappings = other.mappings; - - segments.reserve (other.segments.size ()); - for (const auto &e : other.segments) - segments.push_back (e->clone_type_path_segment ()); - - return *this; - } + QualifiedPathInType &operator= (QualifiedPathInType const &other); // move constructors QualifiedPathInType (QualifiedPathInType &&other) = default; @@ -963,10 +856,7 @@ public: QualifiedPathType &get_path_type () { return path_type; } - std::unique_ptr<TypePathSegment> &get_associated_segment () - { - return associated_segment; - } + TypePathSegment &get_associated_segment () { return *associated_segment; } std::vector<std::unique_ptr<TypePathSegment> > &get_segments () { @@ -974,40 +864,6 @@ public: } }; -class SimplePathSegment -{ - Analysis::NodeMapping mappings; - -public: - SimplePathSegment (Analysis::NodeMapping mappings) : mappings (mappings) {} - - const Analysis::NodeMapping &get_mappings () const { return mappings; } -}; - -class SimplePath -{ - std::vector<SimplePathSegment> segments; - Analysis::NodeMapping mappings; - location_t locus; - -public: - SimplePath (std::vector<SimplePathSegment> segments, - Analysis::NodeMapping mappings, location_t locus) - : segments (std::move (segments)), mappings (mappings), locus (locus) - {} - - static HIR::SimplePath create_empty () - { - return HIR::SimplePath ({}, Analysis::NodeMapping::get_error (), - UNDEF_LOCATION); - } - - bool is_error () const { return segments.empty (); } - - const Analysis::NodeMapping &get_mappings () const { return mappings; } - location_t get_locus () const { return locus; } -}; - } // namespace HIR } // namespace Rust diff --git a/gcc/rust/hir/tree/rust-hir-pattern-abstract.h b/gcc/rust/hir/tree/rust-hir-pattern-abstract.h new file mode 100644 index 0000000..b156a80 --- /dev/null +++ b/gcc/rust/hir/tree/rust-hir-pattern-abstract.h @@ -0,0 +1,82 @@ +// Copyright (C) 2020-2024 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_HIR_PATTERN_ABSTRACT_H +#define RUST_HIR_PATTERN_ABSTRACT_H + +#include "rust-hir-visitable.h" +#include "rust-hir-visitor.h" +#include "rust-hir-node.h" +#include "rust-system.h" + +namespace Rust { +namespace HIR { + +// Pattern base HIR node +class Pattern : public Node, virtual public FullVisitable +{ +public: + using FullVisitable::accept_vis; + + enum PatternType + { + PATH, + LITERAL, + IDENTIFIER, + WILDCARD, + RANGE, + REFERENCE, + STRUCT, + TUPLE_STRUCT, + TUPLE, + GROUPED, + SLICE, + ALT + }; + + BaseKind get_hir_kind () override final { return PATTERN; } + + // Unique pointer custom clone function + std::unique_ptr<Pattern> clone_pattern () const + { + return std::unique_ptr<Pattern> (clone_pattern_impl ()); + } + + // possible virtual methods: is_refutable() + + virtual ~Pattern () {} + + virtual std::string as_string () const = 0; + + virtual void accept_vis (HIRPatternVisitor &vis) = 0; + + virtual const Analysis::NodeMapping &get_mappings () const = 0; + + virtual location_t get_locus () const = 0; + + virtual PatternType get_pattern_type () const = 0; + +protected: + // Clone pattern implementation as pure virtual method + virtual Pattern *clone_pattern_impl () const = 0; +}; + +} // namespace HIR +} // namespace Rust + +#endif diff --git a/gcc/rust/hir/tree/rust-hir-pattern.h b/gcc/rust/hir/tree/rust-hir-pattern.h index e5d8371..5cc5c95 100644 --- a/gcc/rust/hir/tree/rust-hir-pattern.h +++ b/gcc/rust/hir/tree/rust-hir-pattern.h @@ -19,12 +19,13 @@ #ifndef RUST_HIR_PATTERN_H #define RUST_HIR_PATTERN_H +#include "rust-hir-pattern-abstract.h" #include "rust-common.h" -#include "rust-hir.h" +#include "rust-hir-literal.h" +#include "rust-hir-path.h" namespace Rust { namespace HIR { - // Literal pattern HIR node (comparing to a literal) class LiteralPattern : public Pattern { @@ -132,7 +133,7 @@ public: bool is_mut () const { return mut == Mutability::Mut; } bool get_is_ref () const { return is_ref; } - std::unique_ptr<Pattern> &get_to_bind () { return to_bind; } + Pattern &get_to_bind () { return *to_bind; } void accept_vis (HIRFullVisitor &vis) override; void accept_vis (HIRPatternVisitor &vis) override; @@ -405,9 +406,9 @@ public: return PatternType::RANGE; } - std::unique_ptr<RangePatternBound> &get_lower_bound () { return lower; } + RangePatternBound &get_lower_bound () { return *lower; } - std::unique_ptr<RangePatternBound> &get_upper_bound () { return upper; } + RangePatternBound &get_upper_bound () { return *upper; } protected: /* Use covariance to implement clone function as returning this object rather @@ -476,7 +477,7 @@ public: return PatternType::REFERENCE; } - std::unique_ptr<Pattern> &get_referenced_pattern () { return pattern; } + Pattern &get_referenced_pattern () { return *pattern; } protected: /* Use covariance to implement clone function as returning this object rather @@ -572,7 +573,7 @@ public: void accept_vis (HIRFullVisitor &vis) override; TupleIndex get_index () { return index; } - std::unique_ptr<Pattern> &get_tuple_pattern () { return tuple_pattern; } + Pattern &get_tuple_pattern () { return *tuple_pattern; } ItemType get_item_type () const override final { return ItemType::TUPLE_PAT; } @@ -630,7 +631,7 @@ public: Identifier get_identifier () const { return ident; } - std::unique_ptr<Pattern> &get_pattern () { return ident_pattern; } + Pattern &get_pattern () { return *ident_pattern; } protected: /* Use covariance to implement clone function as returning this object rather @@ -1002,7 +1003,7 @@ public: PathInExpression &get_path () { return path; } - std::unique_ptr<TupleStructItems> &get_items () { return items; } + TupleStructItems &get_items () { return *items; } const Analysis::NodeMapping &get_mappings () const override final { @@ -1221,8 +1222,8 @@ public: return PatternType::TUPLE; } - std::unique_ptr<TuplePatternItems> &get_items () { return items; } - const std::unique_ptr<TuplePatternItems> &get_items () const { return items; } + TuplePatternItems &get_items () { return *items; } + const TuplePatternItems &get_items () const { return *items; } protected: /* Use covariance to implement clone function as returning this object rather diff --git a/gcc/rust/hir/tree/rust-hir-simple-path.h b/gcc/rust/hir/tree/rust-hir-simple-path.h new file mode 100644 index 0000000..7f832ff --- /dev/null +++ b/gcc/rust/hir/tree/rust-hir-simple-path.h @@ -0,0 +1,64 @@ +// Copyright (C) 2020-2024 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_HIR_SIMPLE_PATH_H +#define RUST_HIR_SIMPLE_PATH_H + +#include "rust-hir-map.h" + +namespace Rust { +namespace HIR { + +class SimplePathSegment +{ + Analysis::NodeMapping mappings; + +public: + SimplePathSegment (Analysis::NodeMapping mappings) : mappings (mappings) {} + + const Analysis::NodeMapping &get_mappings () const { return mappings; } +}; + +class SimplePath +{ + std::vector<SimplePathSegment> segments; + Analysis::NodeMapping mappings; + location_t locus; + +public: + SimplePath (std::vector<SimplePathSegment> segments, + Analysis::NodeMapping mappings, location_t locus) + : segments (std::move (segments)), mappings (mappings), locus (locus) + {} + + static HIR::SimplePath create_empty () + { + return HIR::SimplePath ({}, Analysis::NodeMapping::get_error (), + UNDEF_LOCATION); + } + + bool is_error () const { return segments.empty (); } + + const Analysis::NodeMapping &get_mappings () const { return mappings; } + location_t get_locus () const { return locus; } +}; + +} // namespace HIR +} // namespace Rust + +#endif diff --git a/gcc/rust/hir/tree/rust-hir-stmt.cc b/gcc/rust/hir/tree/rust-hir-stmt.cc new file mode 100644 index 0000000..fd58e29 --- /dev/null +++ b/gcc/rust/hir/tree/rust-hir-stmt.cc @@ -0,0 +1,114 @@ +// Copyright (C) 2020-2024 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-hir-stmt.h" +#include "optional.h" +#include "rust-system.h" + +namespace Rust { +namespace HIR { + +LetStmt::LetStmt (Analysis::NodeMapping mappings, + std::unique_ptr<Pattern> variables_pattern, + tl::optional<std::unique_ptr<Expr>> init_expr, + tl::optional<std::unique_ptr<Expr>> else_expr, + tl::optional<std::unique_ptr<Type>> type, + AST::AttrVec outer_attrs, location_t locus) + : Stmt (std::move (mappings)), outer_attrs (std::move (outer_attrs)), + variables_pattern (std::move (variables_pattern)), type (std::move (type)), + init_expr (std::move (init_expr)), else_expr (std::move (else_expr)), + locus (locus) +{} + +LetStmt::LetStmt (LetStmt const &other) + : Stmt (other.mappings), outer_attrs (other.outer_attrs), locus (other.locus) +{ + // guard to prevent null dereference (only required if error state) + if (other.variables_pattern != nullptr) + variables_pattern = other.variables_pattern->clone_pattern (); + + // guard to prevent null dereference (always required) + if (other.has_init_expr ()) + init_expr = other.get_init_expr ().clone_expr (); + if (other.has_else_expr ()) + else_expr = other.get_else_expr ().clone_expr (); + + if (other.has_type ()) + type = other.get_type ().clone_type (); + else + type = tl::nullopt; +} + +LetStmt & +LetStmt::operator= (LetStmt const &other) +{ + outer_attrs = other.outer_attrs; + locus = other.locus; + + // guard to prevent null dereference (only required if error state) + if (other.variables_pattern != nullptr) + variables_pattern = other.variables_pattern->clone_pattern (); + else + variables_pattern = nullptr; + + // guard to prevent null dereference (always required) + if (other.has_init_expr ()) + init_expr = other.get_init_expr ().clone_expr (); + else + init_expr = nullptr; + + if (other.has_else_expr ()) + else_expr = other.get_else_expr ().clone_expr (); + else + else_expr = tl::nullopt; + + if (other.has_type ()) + type = other.get_type ().clone_type (); + else + type = tl::nullopt; + + return *this; +} + +ExprStmt::ExprStmt (Analysis::NodeMapping mappings, std::unique_ptr<Expr> expr, + location_t locus, bool must_be_unit) + : Stmt (std::move (mappings)), expr (std::move (expr)), locus (locus), + must_be_unit (must_be_unit) +{} + +ExprStmt::ExprStmt (Analysis::NodeMapping mappings, std::unique_ptr<Expr> expr, + location_t locus) + : ExprStmt (std::move (mappings), std::move (expr), locus, false) +{} + +ExprStmt::ExprStmt (ExprStmt const &other) + : Stmt (other), expr (other.expr->clone_expr ()), locus (other.locus) +{} + +ExprStmt & +ExprStmt::operator= (ExprStmt const &other) +{ + Stmt::operator= (other); + expr = other.expr->clone_expr (); + locus = other.locus; + + return *this; +} + +} // namespace HIR +} // namespace Rust diff --git a/gcc/rust/hir/tree/rust-hir-stmt.h b/gcc/rust/hir/tree/rust-hir-stmt.h index e6e844f..9c1a9ec 100644 --- a/gcc/rust/hir/tree/rust-hir-stmt.h +++ b/gcc/rust/hir/tree/rust-hir-stmt.h @@ -22,9 +22,48 @@ #include "rust-hir.h" #include "rust-hir-path.h" #include "rust-hir-expr.h" +#include "rust-system.h" namespace Rust { namespace HIR { +/* Base statement abstract class. Note that most "statements" are not allowed in + * top-level module scope - only a subclass of statements called "items" are. */ +class Stmt : public Node, public FullVisitable +{ +public: + using FullVisitable::accept_vis; + + // Unique pointer custom clone function + std::unique_ptr<Stmt> clone_stmt () const + { + return std::unique_ptr<Stmt> (clone_stmt_impl ()); + } + + BaseKind get_hir_kind () override { return STMT; } + + virtual ~Stmt () {} + + virtual std::string as_string () const = 0; + + virtual void accept_vis (HIRStmtVisitor &vis) = 0; + + virtual location_t get_locus () const = 0; + + virtual bool is_unit_check_needed () const { return false; } + + const Analysis::NodeMapping &get_mappings () const { return mappings; } + + virtual bool is_item () const = 0; + +protected: + Stmt (Analysis::NodeMapping mappings) : mappings (std::move (mappings)) {} + + // Clone function implementation as pure virtual method + virtual Stmt *clone_stmt_impl () const = 0; + + Analysis::NodeMapping mappings; +}; + // Just a semi-colon, which apparently is a statement. class EmptyStmt : public Stmt { @@ -59,11 +98,10 @@ class LetStmt : public Stmt std::unique_ptr<Pattern> variables_pattern; - // bool has_type; - std::unique_ptr<Type> type; + tl::optional<std::unique_ptr<Type>> type; - // bool has_init_expr; - std::unique_ptr<Expr> init_expr; + tl::optional<std::unique_ptr<Expr>> init_expr; + tl::optional<std::unique_ptr<Expr>> else_expr; location_t locus; @@ -72,62 +110,27 @@ public: bool has_outer_attrs () const { return !outer_attrs.empty (); } // Returns whether let statement has a given return type. - bool has_type () const { return type != nullptr; } + bool has_type () const { return type.has_value (); } // Returns whether let statement has an initialisation expression. - bool has_init_expr () const { return init_expr != nullptr; } + bool has_init_expr () const { return init_expr.has_value (); } + // Returns whether let statement has a diverging else expression. + bool has_else_expr () const { return else_expr.has_value (); } std::string as_string () const override; LetStmt (Analysis::NodeMapping mappings, std::unique_ptr<Pattern> variables_pattern, - std::unique_ptr<Expr> init_expr, std::unique_ptr<Type> type, - AST::AttrVec outer_attrs, location_t locus) - : Stmt (std::move (mappings)), outer_attrs (std::move (outer_attrs)), - variables_pattern (std::move (variables_pattern)), - type (std::move (type)), init_expr (std::move (init_expr)), locus (locus) - {} + tl::optional<std::unique_ptr<Expr>> init_expr, + tl::optional<std::unique_ptr<Expr>> else_expr, + tl::optional<std::unique_ptr<Type>> type, AST::AttrVec outer_attrs, + location_t locus); // Copy constructor with clone - LetStmt (LetStmt const &other) - : Stmt (other.mappings), outer_attrs (other.outer_attrs), - locus (other.locus) - { - // guard to prevent null dereference (only required if error state) - if (other.variables_pattern != nullptr) - variables_pattern = other.variables_pattern->clone_pattern (); - - // guard to prevent null dereference (always required) - if (other.init_expr != nullptr) - init_expr = other.init_expr->clone_expr (); - if (other.type != nullptr) - type = other.type->clone_type (); - } + LetStmt (LetStmt const &other); // Overloaded assignment operator to clone - LetStmt &operator= (LetStmt const &other) - { - outer_attrs = other.outer_attrs; - locus = other.locus; - - // guard to prevent null dereference (only required if error state) - if (other.variables_pattern != nullptr) - variables_pattern = other.variables_pattern->clone_pattern (); - else - variables_pattern = nullptr; - - // guard to prevent null dereference (always required) - if (other.init_expr != nullptr) - init_expr = other.init_expr->clone_expr (); - else - init_expr = nullptr; - if (other.type != nullptr) - type = other.type->clone_type (); - else - type = nullptr; - - return *this; - } + LetStmt &operator= (LetStmt const &other); // move constructors LetStmt (LetStmt &&other) = default; @@ -144,11 +147,43 @@ public: } std::vector<AST::Attribute> &get_outer_attrs () { return outer_attrs; } - std::unique_ptr<HIR::Type> &get_type () { return type; } + HIR::Type &get_type () + { + rust_assert (*type); + return *type.value (); + } + + const HIR::Type &get_type () const + { + rust_assert (*type); + return *type.value (); + } - std::unique_ptr<HIR::Expr> &get_init_expr () { return init_expr; } + HIR::Expr &get_init_expr () + { + rust_assert (*init_expr); + return *init_expr.value (); + } - std::unique_ptr<HIR::Pattern> &get_pattern () { return variables_pattern; } + const HIR::Expr &get_init_expr () const + { + rust_assert (*init_expr); + return *init_expr.value (); + } + + HIR::Expr &get_else_expr () + { + rust_assert (*else_expr); + return *else_expr.value (); + } + + const HIR::Expr &get_else_expr () const + { + rust_assert (*else_expr); + return *else_expr.value (); + } + + HIR::Pattern &get_pattern () { return *variables_pattern; } bool is_item () const override final { return false; } @@ -167,15 +202,10 @@ class ExprStmt : public Stmt public: ExprStmt (Analysis::NodeMapping mappings, std::unique_ptr<Expr> expr, - location_t locus, bool must_be_unit) - : Stmt (std::move (mappings)), expr (std::move (expr)), locus (locus), - must_be_unit (must_be_unit) - {} + location_t locus, bool must_be_unit); ExprStmt (Analysis::NodeMapping mappings, std::unique_ptr<Expr> expr, - location_t locus) - : ExprStmt (std::move (mappings), std::move (expr), locus, false) - {} + location_t locus); std::string as_string () const override; @@ -186,22 +216,13 @@ public: bool is_item () const override final { return false; } - std::unique_ptr<Expr> &get_expr () { return expr; } + Expr &get_expr () { return *expr; } // Copy constructor with clone - ExprStmt (ExprStmt const &other) - : Stmt (other), expr (other.expr->clone_expr ()), locus (other.locus) - {} + ExprStmt (ExprStmt const &other); // Overloaded assignment operator to clone - ExprStmt &operator= (ExprStmt const &other) - { - Stmt::operator= (other); - expr = other.expr->clone_expr (); - locus = other.locus; - - return *this; - } + ExprStmt &operator= (ExprStmt const &other); // move constructors ExprStmt (ExprStmt &&other) = default; diff --git a/gcc/rust/hir/tree/rust-hir-trait-bound.h b/gcc/rust/hir/tree/rust-hir-trait-bound.h new file mode 100644 index 0000000..d20fa79 --- /dev/null +++ b/gcc/rust/hir/tree/rust-hir-trait-bound.h @@ -0,0 +1,87 @@ +// Copyright (C) 2020-2024 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_HIR_TRAIT_BOUND_H +#define RUST_HIR_TRAIT_BOUND_H + +#include "rust-hir-bound-abstract.h" +#include "rust-hir-path.h" +#include "rust-hir-generic-param.h" + +namespace Rust { +namespace HIR { + +// A trait bound +class TraitBound : public TypeParamBound +{ + bool in_parens; + BoundPolarity polarity; + std::vector<LifetimeParam> for_lifetimes; + TypePath type_path; + location_t locus; + + Analysis::NodeMapping mappings; + +public: + // Returns whether trait bound has "for" lifetimes + bool has_for_lifetimes () const { return !for_lifetimes.empty (); } + + TraitBound (Analysis::NodeMapping mapping, TypePath type_path, + location_t locus, bool in_parens = false, + BoundPolarity polarity = BoundPolarity::RegularBound, + std::vector<LifetimeParam> for_lifetimes + = std::vector<LifetimeParam> ()) + : in_parens (in_parens), polarity (polarity), + for_lifetimes (std::move (for_lifetimes)), + type_path (std::move (type_path)), locus (locus), mappings (mapping) + {} + + std::string as_string () const override; + + location_t get_locus () const override final { return locus; } + + void accept_vis (HIRFullVisitor &vis) override; + + Analysis::NodeMapping get_mappings () const override final + { + return mappings; + } + + std::vector<LifetimeParam> &get_for_lifetimes () { return for_lifetimes; } + bool get_in_parens () { return in_parens; } + BoundPolarity get_polarity () { return polarity; } + + BoundType get_bound_type () const final override { return TRAITBOUND; } + + TypePath &get_path () { return type_path; } + + const TypePath &get_path () const { return type_path; } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + TraitBound *clone_type_param_bound_impl () const override + { + return new TraitBound (*this); + } +}; + +} // namespace HIR +} // namespace Rust + +#endif diff --git a/gcc/rust/util/rust-make-unique.h b/gcc/rust/hir/tree/rust-hir-type-abstract.cc index ef58991..901c603 100644 --- a/gcc/rust/util/rust-make-unique.h +++ b/gcc/rust/hir/tree/rust-hir-type-abstract.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2025 Free Software Foundation, Inc. +// Copyright (C) 2020-2024 Free Software Foundation, Inc. // This file is part of GCC. @@ -16,20 +16,17 @@ // along with GCC; see the file COPYING3. If not see // <http://www.gnu.org/licenses/>. -#ifndef RUST_MAKE_UNIQUE_H -#define RUST_MAKE_UNIQUE_H - -#include "rust-system.h" +#include "rust-hir-type-abstract.h" +#include "rust-hir-trait-bound.h" namespace Rust { +namespace HIR { -template <typename T, typename... Ts> -std::unique_ptr<T> -make_unique (Ts &&...params) +std::unique_ptr<TraitBound> +Type::to_trait_bound (bool in_parens ATTRIBUTE_UNUSED) const { - return std::unique_ptr<T> (new T (std::forward<Ts> (params)...)); + return std::unique_ptr<TraitBound> (nullptr); } +} // namespace HIR } // namespace Rust - -#endif // RUST_MAKE_UNIQUE_H diff --git a/gcc/rust/hir/tree/rust-hir-type-abstract.h b/gcc/rust/hir/tree/rust-hir-type-abstract.h new file mode 100644 index 0000000..6142d88 --- /dev/null +++ b/gcc/rust/hir/tree/rust-hir-type-abstract.h @@ -0,0 +1,80 @@ +// Copyright (C) 2020-2024 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_HIR_TYPE_ABSTRACT_H +#define RUST_HIR_TYPE_ABSTRACT_H + +#include "rust-hir-node.h" +#include "rust-hir-visitable.h" +#include "rust-system.h" +#include "rust-hir-map.h" + +namespace Rust { +namespace HIR { + +class TraitBound; + +// Base class for types as represented in HIR - abstract +class Type : public Node, public FullVisitable +{ +public: + using FullVisitable::accept_vis; + // Unique pointer custom clone function + std::unique_ptr<Type> clone_type () const + { + return std::unique_ptr<Type> (clone_type_impl ()); + } + + // virtual destructor + virtual ~Type () {} + + BaseKind get_hir_kind () override final { return TYPE; } + + virtual std::string as_string () const = 0; + + /* HACK: convert to trait bound. Virtual method overriden by classes that + * enable this. */ + virtual std::unique_ptr<TraitBound> + to_trait_bound (bool in_parens ATTRIBUTE_UNUSED) const; + /* as pointer, shouldn't require definition beforehand, only forward + * declaration. */ + + virtual void accept_vis (HIRTypeVisitor &vis) = 0; + + virtual const Analysis::NodeMapping &get_mappings () const + { + return mappings; + } + virtual location_t get_locus () const { return locus; } + +protected: + Type (Analysis::NodeMapping mappings, location_t locus) + : mappings (mappings), locus (locus) + {} + + // Clone function implementation as pure virtual method + virtual Type *clone_type_impl () const = 0; + + Analysis::NodeMapping mappings; + location_t locus; +}; + +} // namespace HIR +} // namespace Rust + +#endif diff --git a/gcc/rust/hir/tree/rust-hir-type-no-bounds.h b/gcc/rust/hir/tree/rust-hir-type-no-bounds.h new file mode 100644 index 0000000..b86ff30 --- /dev/null +++ b/gcc/rust/hir/tree/rust-hir-type-no-bounds.h @@ -0,0 +1,58 @@ + +// Copyright (C) 2020-2024 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_HIR_TYPE_NO_BOUNDS_H +#define RUST_HIR_TYPE_NO_BOUNDS_H + +#include "rust-hir-type-abstract.h" + +namespace Rust { +namespace HIR { + +// A type without parentheses? - abstract +class TypeNoBounds : public Type +{ +public: + // Unique pointer custom clone function + std::unique_ptr<TypeNoBounds> clone_type_no_bounds () const + { + return std::unique_ptr<TypeNoBounds> (clone_type_no_bounds_impl ()); + } + +protected: + TypeNoBounds (Analysis::NodeMapping mappings, location_t locus) + : Type (mappings, locus) + {} + + // Clone function implementation as pure virtual method + virtual TypeNoBounds *clone_type_no_bounds_impl () const = 0; + + /* Save having to specify two clone methods in derived classes by making type + * clone return typenobounds clone. Hopefully won't affect performance too + * much. */ + TypeNoBounds *clone_type_impl () const override + { + return clone_type_no_bounds_impl (); + } +}; + +} // namespace HIR +} // namespace Rust + +#endif diff --git a/gcc/rust/hir/tree/rust-hir-type.cc b/gcc/rust/hir/tree/rust-hir-type.cc new file mode 100644 index 0000000..ec48425 --- /dev/null +++ b/gcc/rust/hir/tree/rust-hir-type.cc @@ -0,0 +1,290 @@ + +// Copyright (C) 2020-2024 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-hir-type.h" + +namespace Rust { +namespace HIR { + +ImplTraitType::ImplTraitType ( + Analysis::NodeMapping mappings, + std::vector<std::unique_ptr<TypeParamBound>> type_param_bounds, + location_t locus) + : Type (mappings, locus), type_param_bounds (std::move (type_param_bounds)) +{} + +ImplTraitType::ImplTraitType (ImplTraitType const &other) + : Type (other.mappings, other.locus) +{ + type_param_bounds.reserve (other.type_param_bounds.size ()); + for (const auto &e : other.type_param_bounds) + type_param_bounds.push_back (e->clone_type_param_bound ()); +} + +ImplTraitType & +ImplTraitType::operator= (ImplTraitType const &other) +{ + locus = other.locus; + mappings = other.mappings; + + type_param_bounds.reserve (other.type_param_bounds.size ()); + for (const auto &e : other.type_param_bounds) + type_param_bounds.push_back (e->clone_type_param_bound ()); + + return *this; +} + +TraitObjectType::TraitObjectType ( + Analysis::NodeMapping mappings, + std::vector<std::unique_ptr<TypeParamBound>> type_param_bounds, + location_t locus, bool is_dyn_dispatch) + : Type (mappings, locus), has_dyn (is_dyn_dispatch), + type_param_bounds (std::move (type_param_bounds)) +{} + +TraitObjectType::TraitObjectType (TraitObjectType const &other) + : Type (other.mappings, other.locus), has_dyn (other.has_dyn) +{ + type_param_bounds.reserve (other.type_param_bounds.size ()); + for (const auto &e : other.type_param_bounds) + type_param_bounds.push_back (e->clone_type_param_bound ()); +} + +TraitObjectType & +TraitObjectType::operator= (TraitObjectType const &other) +{ + mappings = other.mappings; + has_dyn = other.has_dyn; + locus = other.locus; + type_param_bounds.reserve (other.type_param_bounds.size ()); + for (const auto &e : other.type_param_bounds) + type_param_bounds.push_back (e->clone_type_param_bound ()); + + return *this; +} + +ParenthesisedType::ParenthesisedType (Analysis::NodeMapping mappings, + std::unique_ptr<Type> type_inside_parens, + location_t locus) + : TypeNoBounds (mappings, locus), + type_in_parens (std::move (type_inside_parens)) +{} + +ParenthesisedType::ParenthesisedType (ParenthesisedType const &other) + : TypeNoBounds (other.mappings, other.locus), + type_in_parens (other.type_in_parens->clone_type ()) +{} + +ParenthesisedType & +ParenthesisedType::operator= (ParenthesisedType const &other) +{ + mappings = other.mappings; + type_in_parens = other.type_in_parens->clone_type (); + locus = other.locus; + return *this; +} + +std::unique_ptr<TraitBound> +ParenthesisedType::to_trait_bound (bool in_parens ATTRIBUTE_UNUSED) const +{ + /* NOTE: obviously it is unknown whether the internal type is a trait bound + * due to polymorphism, so just let the internal type handle it. As + * parenthesised type, it must be in parentheses. */ + return type_in_parens->to_trait_bound (true); +} + +TupleType::TupleType (Analysis::NodeMapping mappings, + std::vector<std::unique_ptr<Type>> elems, + location_t locus) + : TypeNoBounds (mappings, locus), elems (std::move (elems)) +{} + +TupleType::TupleType (TupleType const &other) + : TypeNoBounds (other.mappings, other.locus) +{ + mappings = other.mappings; + elems.reserve (other.elems.size ()); + for (const auto &e : other.elems) + elems.push_back (e->clone_type ()); +} + +TupleType & +TupleType::operator= (TupleType const &other) +{ + locus = other.locus; + + elems.reserve (other.elems.size ()); + for (const auto &e : other.elems) + elems.push_back (e->clone_type ()); + + return *this; +} + +NeverType::NeverType (Analysis::NodeMapping mappings, location_t locus) + : TypeNoBounds (mappings, locus) +{} + +RawPointerType::RawPointerType (Analysis::NodeMapping mappings, Mutability mut, + std::unique_ptr<Type> type, location_t locus) + : TypeNoBounds (mappings, locus), mut (mut), type (std::move (type)) +{} + +RawPointerType::RawPointerType (RawPointerType const &other) + : TypeNoBounds (other.mappings, other.locus), mut (other.mut), + type (other.type->clone_type ()) +{} + +RawPointerType & +RawPointerType::operator= (RawPointerType const &other) +{ + mappings = other.mappings; + mut = other.mut; + type = other.type->clone_type (); + locus = other.locus; + return *this; +} + +ReferenceType::ReferenceType (Analysis::NodeMapping mappings, Mutability mut, + std::unique_ptr<Type> type_no_bounds, + location_t locus, tl::optional<Lifetime> lifetime) + : TypeNoBounds (mappings, locus), lifetime (std::move (lifetime)), mut (mut), + type (std::move (type_no_bounds)) +{} + +ReferenceType::ReferenceType (ReferenceType const &other) + : TypeNoBounds (other.mappings, other.locus), lifetime (other.lifetime), + mut (other.mut), type (other.type->clone_type ()) +{} + +ReferenceType & +ReferenceType::operator= (ReferenceType const &other) +{ + mappings = other.mappings; + lifetime = other.lifetime; + mut = other.mut; + type = other.type->clone_type (); + locus = other.locus; + + return *this; +} + +ArrayType::ArrayType (Analysis::NodeMapping mappings, + std::unique_ptr<Type> type, + std::unique_ptr<Expr> array_size, location_t locus) + : TypeNoBounds (mappings, locus), elem_type (std::move (type)), + size (std::move (array_size)) +{} + +ArrayType::ArrayType (ArrayType const &other) + : TypeNoBounds (other.mappings, other.locus), + elem_type (other.elem_type->clone_type ()), size (other.size->clone_expr ()) +{} + +ArrayType & +ArrayType::operator= (ArrayType const &other) +{ + mappings = other.mappings; + elem_type = other.elem_type->clone_type (); + size = other.size->clone_expr (); + locus = other.locus; + return *this; +} + +SliceType::SliceType (Analysis::NodeMapping mappings, + std::unique_ptr<Type> type, location_t locus) + : TypeNoBounds (mappings, locus), elem_type (std::move (type)) +{} + +SliceType::SliceType (SliceType const &other) + : TypeNoBounds (other.mappings, other.locus), + elem_type (other.elem_type->clone_type ()) +{} + +SliceType & +SliceType::operator= (SliceType const &other) +{ + mappings = other.mappings; + elem_type = other.elem_type->clone_type (); + locus = other.locus; + + return *this; +} + +InferredType::InferredType (Analysis::NodeMapping mappings, location_t locus) + : TypeNoBounds (mappings, locus) +{} + +MaybeNamedParam::MaybeNamedParam (Identifier name, ParamKind param_kind, + std::unique_ptr<Type> param_type, + location_t locus) + : param_type (std::move (param_type)), param_kind (param_kind), + name (std::move (name)), locus (locus) +{} + +MaybeNamedParam::MaybeNamedParam (MaybeNamedParam const &other) + : param_type (other.param_type->clone_type ()), param_kind (other.param_kind), + name (other.name), locus (other.locus) +{} + +MaybeNamedParam & +MaybeNamedParam::operator= (MaybeNamedParam const &other) +{ + name = other.name; + param_kind = other.param_kind; + param_type = other.param_type->clone_type (); + locus = other.locus; + + return *this; +} + +BareFunctionType::BareFunctionType ( + Analysis::NodeMapping mappings, std::vector<LifetimeParam> lifetime_params, + FunctionQualifiers qualifiers, std::vector<MaybeNamedParam> named_params, + bool is_variadic, std::unique_ptr<Type> type, location_t locus) + : TypeNoBounds (mappings, locus), for_lifetimes (std::move (lifetime_params)), + function_qualifiers (std::move (qualifiers)), + params (std::move (named_params)), is_variadic (is_variadic), + return_type (std::move (type)) +{} + +BareFunctionType::BareFunctionType (BareFunctionType const &other) + : TypeNoBounds (other.mappings, other.locus), + for_lifetimes (other.for_lifetimes), + function_qualifiers (other.function_qualifiers), params (other.params), + is_variadic (other.is_variadic), + return_type (other.has_return_type () ? other.return_type->clone_type () + : nullptr) +{} + +BareFunctionType & +BareFunctionType::operator= (BareFunctionType const &other) +{ + mappings = other.mappings; + for_lifetimes = other.for_lifetimes; + function_qualifiers = other.function_qualifiers; + params = other.params; + is_variadic = other.is_variadic; + return_type = other.return_type->clone_type (); + locus = other.locus; + + return *this; +} + +} // namespace HIR +} // namespace Rust diff --git a/gcc/rust/hir/tree/rust-hir-type.h b/gcc/rust/hir/tree/rust-hir-type.h index e4a9754..cbc20ff 100644 --- a/gcc/rust/hir/tree/rust-hir-type.h +++ b/gcc/rust/hir/tree/rust-hir-type.h @@ -19,73 +19,13 @@ #ifndef RUST_HIR_TYPE_H #define RUST_HIR_TYPE_H +#include "rust-hir-type-abstract.h" #include "rust-common.h" -#include "rust-hir.h" -#include "rust-hir-path.h" +#include "rust-hir-trait-bound.h" +#include "rust-hir-item.h" namespace Rust { namespace HIR { -// definitions moved to rust-ast.h -class TypeParamBound; -class Lifetime; - -// A trait bound -class TraitBound : public TypeParamBound -{ - bool in_parens; - BoundPolarity polarity; - std::vector<LifetimeParam> for_lifetimes; - TypePath type_path; - location_t locus; - - Analysis::NodeMapping mappings; - -public: - // Returns whether trait bound has "for" lifetimes - bool has_for_lifetimes () const { return !for_lifetimes.empty (); } - - TraitBound (Analysis::NodeMapping mapping, TypePath type_path, - location_t locus, bool in_parens = false, - BoundPolarity polarity = BoundPolarity::RegularBound, - std::vector<LifetimeParam> for_lifetimes - = std::vector<LifetimeParam> ()) - : in_parens (in_parens), polarity (polarity), - for_lifetimes (std::move (for_lifetimes)), - type_path (std::move (type_path)), locus (locus), mappings (mapping) - {} - - std::string as_string () const override; - - location_t get_locus () const override final { return locus; } - - void accept_vis (HIRFullVisitor &vis) override; - - Analysis::NodeMapping get_mappings () const override final - { - return mappings; - } - - std::vector<LifetimeParam> &get_for_lifetimes () { return for_lifetimes; } - bool get_in_parens () { return in_parens; } - BoundPolarity get_polarity () { return polarity; } - - BoundType get_bound_type () const final override { return TRAITBOUND; } - - TypePath &get_path () { return type_path; } - - const TypePath &get_path () const { return type_path; } - -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - TraitBound *clone_type_param_bound_impl () const override - { - return new TraitBound (*this); - } -}; - -// definition moved to rust-ast.h -class TypeNoBounds; // An impl trait? Poor reference material here. class ImplTraitType : public Type @@ -105,31 +45,13 @@ protected: public: ImplTraitType (Analysis::NodeMapping mappings, std::vector<std::unique_ptr<TypeParamBound>> type_param_bounds, - location_t locus) - : Type (mappings, locus), type_param_bounds (std::move (type_param_bounds)) - {} + location_t locus); // copy constructor with vector clone - ImplTraitType (ImplTraitType const &other) - : Type (other.mappings, other.locus) - { - type_param_bounds.reserve (other.type_param_bounds.size ()); - for (const auto &e : other.type_param_bounds) - type_param_bounds.push_back (e->clone_type_param_bound ()); - } + ImplTraitType (ImplTraitType const &other); // overloaded assignment operator to clone - ImplTraitType &operator= (ImplTraitType const &other) - { - locus = other.locus; - mappings = other.mappings; - - type_param_bounds.reserve (other.type_param_bounds.size ()); - for (const auto &e : other.type_param_bounds) - type_param_bounds.push_back (e->clone_type_param_bound ()); - - return *this; - } + ImplTraitType &operator= (ImplTraitType const &other); // move constructors ImplTraitType (ImplTraitType &&other) = default; @@ -162,32 +84,13 @@ public: TraitObjectType ( Analysis::NodeMapping mappings, std::vector<std::unique_ptr<TypeParamBound>> type_param_bounds, - location_t locus, bool is_dyn_dispatch) - : Type (mappings, locus), has_dyn (is_dyn_dispatch), - type_param_bounds (std::move (type_param_bounds)) - {} + location_t locus, bool is_dyn_dispatch); // copy constructor with vector clone - TraitObjectType (TraitObjectType const &other) - : Type (other.mappings, other.locus), has_dyn (other.has_dyn) - { - type_param_bounds.reserve (other.type_param_bounds.size ()); - for (const auto &e : other.type_param_bounds) - type_param_bounds.push_back (e->clone_type_param_bound ()); - } + TraitObjectType (TraitObjectType const &other); // overloaded assignment operator to clone - TraitObjectType &operator= (TraitObjectType const &other) - { - mappings = other.mappings; - has_dyn = other.has_dyn; - locus = other.locus; - type_param_bounds.reserve (other.type_param_bounds.size ()); - for (const auto &e : other.type_param_bounds) - type_param_bounds.push_back (e->clone_type_param_bound ()); - - return *this; - } + TraitObjectType &operator= (TraitObjectType const &other); // move constructors TraitObjectType (TraitObjectType &&other) = default; @@ -233,26 +136,15 @@ protected: public: // Constructor uses Type pointer for polymorphism ParenthesisedType (Analysis::NodeMapping mappings, - std::unique_ptr<Type> type_inside_parens, location_t locus) - : TypeNoBounds (mappings, locus), - type_in_parens (std::move (type_inside_parens)) - {} + std::unique_ptr<Type> type_inside_parens, + location_t locus); /* Copy constructor uses custom deep copy method for type to preserve * polymorphism */ - ParenthesisedType (ParenthesisedType const &other) - : TypeNoBounds (other.mappings, other.locus), - type_in_parens (other.type_in_parens->clone_type ()) - {} + ParenthesisedType (ParenthesisedType const &other); // overload assignment operator to use custom clone method - ParenthesisedType &operator= (ParenthesisedType const &other) - { - mappings = other.mappings; - type_in_parens = other.type_in_parens->clone_type (); - locus = other.locus; - return *this; - } + ParenthesisedType &operator= (ParenthesisedType const &other); // default move semantics ParenthesisedType (ParenthesisedType &&other) = default; @@ -264,52 +156,14 @@ public: } // Creates a trait bound (clone of this one's trait bound) - HACK - TraitBound *to_trait_bound (bool in_parens ATTRIBUTE_UNUSED) const override - { - /* NOTE: obviously it is unknown whether the internal type is a trait bound - * due to polymorphism, so just let the internal type handle it. As - * parenthesised type, it must be in parentheses. */ - return type_in_parens->to_trait_bound (true); - } - std::unique_ptr<Type> &get_type_in_parens () { return type_in_parens; } - void accept_vis (HIRFullVisitor &vis) override; - void accept_vis (HIRTypeVisitor &vis) override; -}; - -// Impl trait with a single bound? Poor reference material here. -class ImplTraitTypeOneBound : public TypeNoBounds -{ - TraitBound trait_bound; - -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - ImplTraitTypeOneBound *clone_type_impl () const override - { - return new ImplTraitTypeOneBound (*this); - } + std::unique_ptr<TraitBound> + to_trait_bound (bool in_parens ATTRIBUTE_UNUSED) const override; - /* Use covariance to implement clone function as returning this object rather - * than base */ - ImplTraitTypeOneBound *clone_type_no_bounds_impl () const override - { - return new ImplTraitTypeOneBound (*this); - } - -public: - ImplTraitTypeOneBound (Analysis::NodeMapping mappings, TraitBound trait_bound, - location_t locus) - : TypeNoBounds (mappings, locus), trait_bound (std::move (trait_bound)) - {} - - std::string as_string () const override; - TraitBound &get_trait_bound () { return trait_bound; } + Type &get_type_in_parens () { return *type_in_parens; } void accept_vis (HIRFullVisitor &vis) override; void accept_vis (HIRTypeVisitor &vis) override; }; -class TypePath; // definition moved to "rust-path.h" - /* A type consisting of the "product" of others (the tuple's elements) in a * specific order */ class TupleType : public TypeNoBounds @@ -321,31 +175,13 @@ public: bool is_unit_type () const { return elems.empty (); } TupleType (Analysis::NodeMapping mappings, - std::vector<std::unique_ptr<Type>> elems, location_t locus) - : TypeNoBounds (mappings, locus), elems (std::move (elems)) - {} + std::vector<std::unique_ptr<Type>> elems, location_t locus); // copy constructor with vector clone - TupleType (TupleType const &other) - : TypeNoBounds (other.mappings, other.locus) - { - mappings = other.mappings; - elems.reserve (other.elems.size ()); - for (const auto &e : other.elems) - elems.push_back (e->clone_type ()); - } + TupleType (TupleType const &other); // overloaded assignment operator to clone - TupleType &operator= (TupleType const &other) - { - locus = other.locus; - - elems.reserve (other.elems.size ()); - for (const auto &e : other.elems) - elems.push_back (e->clone_type ()); - - return *this; - } + TupleType &operator= (TupleType const &other); // move constructors TupleType (TupleType &&other) = default; @@ -390,9 +226,7 @@ protected: } public: - NeverType (Analysis::NodeMapping mappings, location_t locus) - : TypeNoBounds (mappings, locus) - {} + NeverType (Analysis::NodeMapping mappings, location_t locus); std::string as_string () const override { return "! (never type)"; } @@ -410,25 +244,13 @@ private: public: // Constructor requires pointer for polymorphism reasons RawPointerType (Analysis::NodeMapping mappings, Mutability mut, - std::unique_ptr<Type> type, location_t locus) - : TypeNoBounds (mappings, locus), mut (mut), type (std::move (type)) - {} + std::unique_ptr<Type> type, location_t locus); // Copy constructor calls custom polymorphic clone function - RawPointerType (RawPointerType const &other) - : TypeNoBounds (other.mappings, other.locus), mut (other.mut), - type (other.type->clone_type ()) - {} + RawPointerType (RawPointerType const &other); // overload assignment operator to use custom clone method - RawPointerType &operator= (RawPointerType const &other) - { - mappings = other.mappings; - mut = other.mut; - type = other.type->clone_type (); - locus = other.locus; - return *this; - } + RawPointerType &operator= (RawPointerType const &other); // default move semantics RawPointerType (RawPointerType &&other) = default; @@ -439,7 +261,7 @@ public: void accept_vis (HIRFullVisitor &vis) override; void accept_vis (HIRTypeVisitor &vis) override; - std::unique_ptr<Type> &get_type () { return type; } + Type &get_type () { return *type; } Mutability get_mut () const { return mut; } @@ -447,7 +269,7 @@ public: bool is_const () const { return mut == Mutability::Imm; } - std::unique_ptr<Type> &get_base_type () { return type; } + Type &get_base_type () { return *type; } protected: /* Use covariance to implement clone function as returning this object rather @@ -469,7 +291,7 @@ protected: class ReferenceType : public TypeNoBounds { // bool has_lifetime; // TODO: handle in lifetime or something? - Lifetime lifetime; + tl::optional<Lifetime> lifetime; Mutability mut; std::unique_ptr<Type> type; @@ -479,33 +301,18 @@ public: bool is_mut () const { return mut == Mutability::Mut; } // Returns whether the reference has a lifetime. - bool has_lifetime () const { return !lifetime.is_error (); } + bool has_lifetime () const { return lifetime.has_value (); } // Constructor ReferenceType (Analysis::NodeMapping mappings, Mutability mut, std::unique_ptr<Type> type_no_bounds, location_t locus, - Lifetime lifetime) - : TypeNoBounds (mappings, locus), lifetime (std::move (lifetime)), - mut (mut), type (std::move (type_no_bounds)) - {} + tl::optional<Lifetime> lifetime); // Copy constructor with custom clone method - ReferenceType (ReferenceType const &other) - : TypeNoBounds (other.mappings, other.locus), lifetime (other.lifetime), - mut (other.mut), type (other.type->clone_type ()) - {} + ReferenceType (ReferenceType const &other); // Operator overload assignment operator to custom clone the unique pointer - ReferenceType &operator= (ReferenceType const &other) - { - mappings = other.mappings; - lifetime = other.lifetime; - mut = other.mut; - type = other.type->clone_type (); - locus = other.locus; - - return *this; - } + ReferenceType &operator= (ReferenceType const &other); // move constructors ReferenceType (ReferenceType &&other) = default; @@ -516,11 +323,12 @@ public: void accept_vis (HIRFullVisitor &vis) override; void accept_vis (HIRTypeVisitor &vis) override; - Lifetime &get_lifetime () { return lifetime; } + Lifetime &get_lifetime () { return lifetime.value (); } + const Lifetime &get_lifetime () const { return lifetime.value (); } Mutability get_mut () const { return mut; } - std::unique_ptr<Type> &get_base_type () { return type; } + Type &get_base_type () { return *type; } protected: /* Use covariance to implement clone function as returning this object rather @@ -547,27 +355,13 @@ class ArrayType : public TypeNoBounds public: // Constructor requires pointers for polymorphism ArrayType (Analysis::NodeMapping mappings, std::unique_ptr<Type> type, - std::unique_ptr<Expr> array_size, location_t locus) - : TypeNoBounds (mappings, locus), elem_type (std::move (type)), - size (std::move (array_size)) - {} + std::unique_ptr<Expr> array_size, location_t locus); // Copy constructor requires deep copies of both unique pointers - ArrayType (ArrayType const &other) - : TypeNoBounds (other.mappings, other.locus), - elem_type (other.elem_type->clone_type ()), - size (other.size->clone_expr ()) - {} + ArrayType (ArrayType const &other); // Overload assignment operator to deep copy pointers - ArrayType &operator= (ArrayType const &other) - { - mappings = other.mappings; - elem_type = other.elem_type->clone_type (); - size = other.size->clone_expr (); - locus = other.locus; - return *this; - } + ArrayType &operator= (ArrayType const &other); // move constructors ArrayType (ArrayType &&other) = default; @@ -578,9 +372,9 @@ public: void accept_vis (HIRFullVisitor &vis) override; void accept_vis (HIRTypeVisitor &vis) override; - std::unique_ptr<Type> &get_element_type () { return elem_type; } + Type &get_element_type () { return *elem_type; } - std::unique_ptr<Expr> &get_size_expr () { return size; } + Expr &get_size_expr () { return *size; } protected: /* Use covariance to implement clone function as returning this object rather @@ -604,25 +398,13 @@ class SliceType : public TypeNoBounds public: // Constructor requires pointer for polymorphism SliceType (Analysis::NodeMapping mappings, std::unique_ptr<Type> type, - location_t locus) - : TypeNoBounds (mappings, locus), elem_type (std::move (type)) - {} + location_t locus); // Copy constructor requires deep copy of Type smart pointer - SliceType (SliceType const &other) - : TypeNoBounds (other.mappings, other.locus), - elem_type (other.elem_type->clone_type ()) - {} + SliceType (SliceType const &other); // Overload assignment operator to deep copy - SliceType &operator= (SliceType const &other) - { - mappings = other.mappings; - elem_type = other.elem_type->clone_type (); - locus = other.locus; - - return *this; - } + SliceType &operator= (SliceType const &other); // move constructors SliceType (SliceType &&other) = default; @@ -633,7 +415,7 @@ public: void accept_vis (HIRFullVisitor &vis) override; void accept_vis (HIRTypeVisitor &vis) override; - std::unique_ptr<Type> &get_element_type () { return elem_type; } + Type &get_element_type () { return *elem_type; } protected: /* Use covariance to implement clone function as returning this object rather @@ -669,9 +451,7 @@ protected: } public: - InferredType (Analysis::NodeMapping mappings, location_t locus) - : TypeNoBounds (mappings, locus) - {} + InferredType (Analysis::NodeMapping mappings, location_t locus); std::string as_string () const override; @@ -679,8 +459,6 @@ public: void accept_vis (HIRTypeVisitor &vis) override; }; -class QualifiedPathInType; // definition moved to "rust-path.h" - // A possibly named param used in a BaseFunctionType struct MaybeNamedParam { @@ -702,29 +480,15 @@ private: public: MaybeNamedParam (Identifier name, ParamKind param_kind, - std::unique_ptr<Type> param_type, location_t locus) - : param_type (std::move (param_type)), param_kind (param_kind), - name (std::move (name)), locus (locus) - {} + std::unique_ptr<Type> param_type, location_t locus); // Copy constructor with clone - MaybeNamedParam (MaybeNamedParam const &other) - : param_type (other.param_type->clone_type ()), - param_kind (other.param_kind), name (other.name), locus (other.locus) - {} + MaybeNamedParam (MaybeNamedParam const &other); ~MaybeNamedParam () = default; // Overloaded assignment operator with clone - MaybeNamedParam &operator= (MaybeNamedParam const &other) - { - name = other.name; - param_kind = other.param_kind; - param_type = other.param_type->clone_type (); - locus = other.locus; - - return *this; - } + MaybeNamedParam &operator= (MaybeNamedParam const &other); // move constructors MaybeNamedParam (MaybeNamedParam &&other) = default; @@ -743,7 +507,7 @@ public: location_t get_locus () const { return locus; } - std::unique_ptr<Type> &get_type () { return param_type; } + Type &get_type () { return *param_type; } ParamKind get_param_kind () const { return param_kind; } @@ -777,36 +541,13 @@ public: std::vector<LifetimeParam> lifetime_params, FunctionQualifiers qualifiers, std::vector<MaybeNamedParam> named_params, bool is_variadic, - std::unique_ptr<Type> type, location_t locus) - : TypeNoBounds (mappings, locus), - for_lifetimes (std::move (lifetime_params)), - function_qualifiers (std::move (qualifiers)), - params (std::move (named_params)), is_variadic (is_variadic), - return_type (std::move (type)) - {} + std::unique_ptr<Type> type, location_t locus); // Copy constructor with clone - BareFunctionType (BareFunctionType const &other) - : TypeNoBounds (other.mappings, other.locus), - for_lifetimes (other.for_lifetimes), - function_qualifiers (other.function_qualifiers), params (other.params), - is_variadic (other.is_variadic), - return_type (other.return_type->clone_type ()) - {} + BareFunctionType (BareFunctionType const &other); // Overload assignment operator to deep copy - BareFunctionType &operator= (BareFunctionType const &other) - { - mappings = other.mappings; - for_lifetimes = other.for_lifetimes; - function_qualifiers = other.function_qualifiers; - params = other.params; - is_variadic = other.is_variadic; - return_type = other.return_type->clone_type (); - locus = other.locus; - - return *this; - } + BareFunctionType &operator= (BareFunctionType const &other); // move constructors BareFunctionType (BareFunctionType &&other) = default; @@ -828,7 +569,7 @@ public: } // TODO: would a "vis_type" be better? - std::unique_ptr<Type> &get_return_type () { return return_type; } + Type &get_return_type () { return *return_type; } protected: /* Use covariance to implement clone function as returning this object rather diff --git a/gcc/rust/hir/tree/rust-hir-visibility.h b/gcc/rust/hir/tree/rust-hir-visibility.h new file mode 100644 index 0000000..a750d88 --- /dev/null +++ b/gcc/rust/hir/tree/rust-hir-visibility.h @@ -0,0 +1,80 @@ +// Copyright (C) 2020-2024 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_HIR_VISIBILITY_H +#define RUST_HIR_VISIBILITY_H + +#include "rust-hir-simple-path.h" + +namespace Rust { +namespace HIR { +// Visibility of an item +struct Visibility +{ +public: + enum VisType + { + PRIVATE, + PUBLIC, + RESTRICTED, + ERROR, + }; + +private: + VisType vis_type; + HIR::SimplePath path; + location_t locus; + + // should this store location info? + +public: + Visibility (VisType vis_type, + HIR::SimplePath path = HIR::SimplePath::create_empty (), + location_t locus = UNDEF_LOCATION) + : vis_type (vis_type), path (std::move (path)), locus (locus) + {} + + // Returns whether visibility is in an error state. + bool is_error () const { return vis_type == ERROR; } + + // Does the current visibility refer to a simple `pub <item>` entirely public + bool is_public () const { return vis_type == PUBLIC; } + + // Is the current visibility public restricted to a certain path + bool is_restricted () const { return vis_type == RESTRICTED; } + + // Creates an error visibility. + static Visibility create_error () + { + return Visibility (ERROR, HIR::SimplePath::create_empty ()); + } + + VisType get_vis_type () const { return vis_type; } + + const HIR::SimplePath &get_path () const + { + rust_assert (!is_error ()); + return path; + } + + std::string as_string () const; +}; +} // namespace HIR +} // namespace Rust + +#endif diff --git a/gcc/rust/hir/tree/rust-hir-visitable.h b/gcc/rust/hir/tree/rust-hir-visitable.h new file mode 100644 index 0000000..9c05cbf --- /dev/null +++ b/gcc/rust/hir/tree/rust-hir-visitable.h @@ -0,0 +1,41 @@ +// Copyright (C) 2020-2024 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_HIR_VISITABLE_H +#define RUST_HIR_VISITABLE_H + +namespace Rust { +namespace HIR { + +class HIRFullVisitor; +class HIRTraitItemVisitor; +class HIRImplVisitor; +class HIRStmtVisitor; +class HIRExpressionVisitor; +class HIRTypeVisitor; +class HIRPatternVisitor; + +class FullVisitable +{ +public: + virtual void accept_vis (HIRFullVisitor &vis) = 0; +}; +} // namespace HIR +} // namespace Rust + +#endif diff --git a/gcc/rust/hir/tree/rust-hir-visitor.h b/gcc/rust/hir/tree/rust-hir-visitor.h index 72609f4..283cc34 100644 --- a/gcc/rust/hir/tree/rust-hir-visitor.h +++ b/gcc/rust/hir/tree/rust-hir-visitor.h @@ -19,7 +19,6 @@ #ifndef RUST_HIR_VISITOR_H #define RUST_HIR_VISITOR_H -#include "rust-hir-expr.h" #include "rust-hir-full-decls.h" namespace Rust { @@ -81,12 +80,11 @@ public: virtual void visit (WhileLetLoopExpr &expr) = 0; virtual void visit (IfExpr &expr) = 0; virtual void visit (IfExprConseqElse &expr) = 0; - virtual void visit (IfLetExpr &expr) = 0; - virtual void visit (IfLetExprConseqElse &expr) = 0; virtual void visit (MatchExpr &expr) = 0; virtual void visit (AwaitExpr &expr) = 0; virtual void visit (AsyncBlockExpr &expr) = 0; virtual void visit (InlineAsm &expr) = 0; + virtual void visit (LlvmInlineAsm &expr) = 0; virtual void visit (TypeParam ¶m) = 0; virtual void visit (ConstGenericParam ¶m) = 0; virtual void visit (LifetimeWhereClauseItem &item) = 0; @@ -145,7 +143,6 @@ public: virtual void visit (ImplTraitType &type) = 0; virtual void visit (TraitObjectType &type) = 0; virtual void visit (ParenthesisedType &type) = 0; - virtual void visit (ImplTraitTypeOneBound &type) = 0; virtual void visit (TupleType &type) = 0; virtual void visit (NeverType &type) = 0; virtual void visit (RawPointerType &type) = 0; @@ -219,13 +216,12 @@ public: virtual void visit (WhileLetLoopExpr &) override {} virtual void visit (IfExpr &) override {} virtual void visit (IfExprConseqElse &) override {} - virtual void visit (IfLetExpr &) override {} - virtual void visit (IfLetExprConseqElse &) override {} virtual void visit (MatchExpr &) override {} virtual void visit (AwaitExpr &) override {} virtual void visit (AsyncBlockExpr &) override {} virtual void visit (InlineAsm &) override {} + virtual void visit (LlvmInlineAsm &) override {} virtual void visit (TypeParam &) override {} virtual void visit (ConstGenericParam &) override {} @@ -295,7 +291,6 @@ public: virtual void visit (ImplTraitType &) override {} virtual void visit (TraitObjectType &) override {} virtual void visit (ParenthesisedType &) override {} - virtual void visit (ImplTraitTypeOneBound &) override {} virtual void visit (TupleType &) override {} virtual void visit (NeverType &) override {} virtual void visit (RawPointerType &) override {} @@ -359,7 +354,6 @@ public: virtual void visit (ImplTraitType &type) = 0; virtual void visit (TraitObjectType &type) = 0; virtual void visit (ParenthesisedType &type) = 0; - virtual void visit (ImplTraitTypeOneBound &type) = 0; virtual void visit (TupleType &type) = 0; virtual void visit (NeverType &type) = 0; virtual void visit (RawPointerType &type) = 0; @@ -448,8 +442,8 @@ public: virtual void visit (WhileLetLoopExpr &expr) = 0; virtual void visit (IfExpr &expr) = 0; virtual void visit (IfExprConseqElse &expr) = 0; - virtual void visit (IfLetExpr &expr) = 0; - virtual void visit (IfLetExprConseqElse &expr) = 0; + virtual void visit (InlineAsm &expr) = 0; + virtual void visit (LlvmInlineAsm &expr) = 0; virtual void visit (MatchExpr &expr) = 0; virtual void visit (AwaitExpr &expr) = 0; virtual void visit (AsyncBlockExpr &expr) = 0; diff --git a/gcc/rust/hir/tree/rust-hir.cc b/gcc/rust/hir/tree/rust-hir.cc index ac0a256..093d8d5 100644 --- a/gcc/rust/hir/tree/rust-hir.cc +++ b/gcc/rust/hir/tree/rust-hir.cc @@ -19,6 +19,7 @@ #include "rust-ast-full.h" #include "rust-hir-expr.h" #include "rust-hir-full.h" +#include "rust-hir-path.h" #include "rust-hir-visitor.h" #include "rust-diagnostics.h" @@ -70,6 +71,33 @@ get_string_in_delims (std::string str_input, AST::DelimType delim_type) rust_unreachable (); } +Crate::Crate (std::vector<std::unique_ptr<Item>> items, + AST::AttrVec inner_attrs, Analysis::NodeMapping mappings) + : WithInnerAttrs (std::move (inner_attrs)), items (std::move (items)), + mappings (mappings) +{} + +Crate::Crate (Crate const &other) + : WithInnerAttrs (other.inner_attrs), mappings (other.mappings) +{ + items.reserve (other.items.size ()); + for (const auto &e : other.items) + items.push_back (e->clone_item ()); +} + +Crate & +Crate::operator= (Crate const &other) +{ + inner_attrs = other.inner_attrs; + mappings = other.mappings; + + items.reserve (other.items.size ()); + for (const auto &e : other.items) + items.push_back (e->clone_item ()); + + return *this; +} + std::string Crate::as_string () const { @@ -213,6 +241,44 @@ Module::as_string () const } std::string +Item::item_kind_string (Item::ItemKind kind) +{ + switch (kind) + { + case Item::ItemKind::Static: + return "static"; + case Item::ItemKind::Constant: + return "constant"; + case Item::ItemKind::TypeAlias: + return "type alias"; + case Item::ItemKind::Function: + return "function"; + case Item::ItemKind::UseDeclaration: + return "use declaration"; + case Item::ItemKind::ExternBlock: + return "extern block"; + case Item::ItemKind::ExternCrate: + return "extern crate"; + case Item::ItemKind::Struct: + return "struct"; + case Item::ItemKind::Union: + return "union"; + case Item::ItemKind::Enum: + return "enum"; + case Item::ItemKind::EnumItem: + return "enum item"; + case Item::ItemKind::Trait: + return "trait"; + case Item::ItemKind::Impl: + return "impl"; + case Item::ItemKind::Module: + return "module"; + default: + rust_unreachable (); + } +} + +std::string StaticItem::as_string () const { std::string str = VisItem::as_string (); @@ -1145,6 +1211,9 @@ ClosureExpr::as_string () const std::string PathPattern::as_string () const { + if (is_lang_item ()) + return LangItem::PrettyString (*lang_item); + std::string str; for (const auto &segment : segments) @@ -1245,7 +1314,7 @@ ContinueExpr::as_string () const if (has_label ()) { - str += label.as_string (); + str += get_label ().as_string (); } return str; @@ -1534,41 +1603,6 @@ IfExprConseqElse::as_string () const } std::string -IfLetExpr::as_string () const -{ - std::string str ("IfLetExpr: "); - - str += "\n Condition match arm patterns: "; - if (match_arm_patterns.empty ()) - { - str += "none"; - } - else - { - for (const auto &pattern : match_arm_patterns) - { - str += "\n " + pattern->as_string (); - } - } - - str += "\n Scrutinee expr: " + value->as_string (); - - str += "\n If let block expr: " + if_block->as_string (); - - return str; -} - -std::string -IfLetExprConseqElse::as_string () const -{ - std::string str = IfLetExpr::as_string (); - - str += "\n Else expr: " + else_block->as_string (); - - return str; -} - -std::string RangeFromToInclExpr::as_string () const { return from->as_string () + "..=" + to->as_string (); @@ -1670,7 +1704,7 @@ WhileLoopExpr::as_string () const } else { - str += loop_label.as_string (); + str += get_loop_label ().as_string (); } str += "\n Conditional expr: " + condition->as_string (); @@ -1692,7 +1726,7 @@ WhileLetLoopExpr::as_string () const } else { - str += loop_label.as_string (); + str += get_loop_label ().as_string (); } str += "\n Match arm patterns: "; @@ -1727,7 +1761,7 @@ LoopExpr::as_string () const } else { - str += loop_label.as_string (); + str += get_loop_label ().as_string (); } str += "\n Loop block: " + loop_block->as_string (); @@ -1782,7 +1816,7 @@ BreakExpr::as_string () const if (has_label ()) { - str += label.as_string () + " "; + str += get_label ().as_string () + " "; } if (has_break_expr ()) @@ -2017,14 +2051,19 @@ LifetimeParam::as_string () const { std::string str ("LifetimeParam: "); - str += "\n Outer attribute: "; - if (!has_outer_attribute ()) + str += "\n Outer attributes: "; + if (outer_attrs.empty ()) { str += "none"; } else { - str += outer_attr.as_string (); + /* note that this does not print them with "outer attribute" syntax - + * just the body */ + for (const auto &attr : outer_attrs) + { + str += "\n " + attr.as_string (); + } } str += "\n Lifetime: " + lifetime.as_string (); @@ -2062,11 +2101,6 @@ QualifiedPathInType::as_string () const std::string Lifetime::as_string () const { - if (is_error ()) - { - return "error lifetime"; - } - switch (lifetime_type) { case AST::Lifetime::LifetimeType::NAMED: @@ -2106,14 +2140,19 @@ TypeParam::as_string () const { std::string str ("TypeParam: "); - str += "\n Outer attribute: "; - if (!has_outer_attribute ()) + str += "\n Outer attributes: "; + if (outer_attrs.empty ()) { str += "none"; } else { - str += outer_attr.as_string (); + /* note that this does not print them with "outer attribute" syntax - + * just the body */ + for (const auto &attr : outer_attrs) + { + str += "\n " + attr.as_string (); + } } str += "\n Identifier: " + type_representation.as_string (); @@ -2138,7 +2177,7 @@ TypeParam::as_string () const } else { - str += type->as_string (); + str += type.value ()->as_string (); } return str; @@ -2147,6 +2186,8 @@ TypeParam::as_string () const AST::SimplePath PathPattern::convert_to_simple_path (bool with_opening_scope_resolution) const { + rust_assert (kind == Kind::Segmented); + if (!has_segments ()) { return AST::SimplePath::create_empty (); @@ -2629,12 +2670,12 @@ LetStmt::as_string () const if (has_type ()) { - str += " : " + type->as_string (); + str += " : " + get_type ().as_string (); } if (has_init_expr ()) { - str += " = " + init_expr->as_string (); + str += " = " + get_init_expr ().as_string (); } return str; @@ -2664,14 +2705,14 @@ Expr::as_string () const } // hopefully definition here will prevent circular dependency issue -TraitBound * +std::unique_ptr<TraitBound> TypePath::to_trait_bound (bool in_parens) const { // create clone FIXME is this required? or is copy constructor automatically // called? TypePath copy (*this); - return new TraitBound (mappings, std::move (copy), copy.get_locus (), - in_parens); + return std::make_unique<TraitBound> (mappings, std::move (copy), + copy.get_locus (), in_parens); } std::string @@ -2714,7 +2755,7 @@ ReferenceType::as_string () const if (has_lifetime ()) { - str += lifetime.as_string () + " "; + str += get_lifetime ().as_string () + " "; } if (is_mut ()) @@ -2820,14 +2861,6 @@ BareFunctionType::as_string () const } std::string -ImplTraitTypeOneBound::as_string () const -{ - std::string str ("ImplTraitTypeOneBound: \n TraitBound: "); - - return str + trait_bound.as_string (); -} - -std::string TypePathSegmentGeneric::as_string () const { return TypePathSegment::as_string () + "<" + generic_args.as_string () + ">"; @@ -2999,7 +3032,7 @@ StructExprStructFields::as_string () const } else { - str += struct_base->as_string (); + str += (*struct_base)->as_string (); } return str; @@ -3373,7 +3406,7 @@ TraitFunctionDecl::as_string () const str += "\n Function params: "; if (is_method ()) { - str += self.as_string () + (has_params () ? ", " : ""); + str += get_self_unchecked ().as_string () + (has_params () ? ", " : ""); } if (has_params ()) @@ -3487,70 +3520,63 @@ TraitItemType::as_string () const std::string SelfParam::as_string () const { - if (is_error ()) - { - return "error"; - } - else + if (has_type ()) { - if (has_type ()) + // type (i.e. not ref, no lifetime) + std::string str; + + if (is_mut ()) { - // type (i.e. not ref, no lifetime) - std::string str; + str += "mut "; + } - if (is_mut ()) - { - str += "mut "; - } + str += "self : "; - str += "self : "; + str += type->as_string (); - str += type->as_string (); + return str; + } + else if (has_lifetime ()) + { + // ref and lifetime + std::string str = "&" + get_lifetime ().as_string () + " "; - return str; - } - else if (has_lifetime ()) + if (is_mut ()) { - // ref and lifetime - std::string str = "&" + lifetime.as_string () + " "; + str += "mut "; + } - if (is_mut ()) - { - str += "mut "; - } + str += "self"; - str += "self"; + return str; + } + else if (is_ref ()) + { + // ref with no lifetime + std::string str = "&"; - return str; - } - else if (is_ref ()) + if (is_mut ()) { - // ref with no lifetime - std::string str = "&"; + str += " mut "; + } - if (is_mut ()) - { - str += " mut "; - } + str += "self"; - str += "self"; + return str; + } + else + { + // no ref, no type + std::string str; - return str; - } - else + if (is_mut ()) { - // no ref, no type - std::string str; - - if (is_mut ()) - { - str += "mut "; - } + str += "mut "; + } - str += "self"; + str += "self"; - return str; - } + return str; } } @@ -3785,7 +3811,9 @@ BorrowExpr::accept_vis (HIRFullVisitor &vis) void InlineAsm::accept_vis (HIRExpressionVisitor &vis) -{} +{ + vis.visit (*this); +} void InlineAsm::accept_vis (HIRFullVisitor &vis) @@ -3794,6 +3822,17 @@ InlineAsm::accept_vis (HIRFullVisitor &vis) } void +LlvmInlineAsm::accept_vis (HIRFullVisitor &vis) +{ + vis.visit (*this); +} +void +LlvmInlineAsm::accept_vis (HIRExpressionVisitor &vis) +{ + vis.visit (*this); +} + +void BorrowExpr::accept_vis (HIRExpressionVisitor &vis) { vis.visit (*this); @@ -3980,6 +4019,12 @@ StructExprStructBase::accept_vis (HIRFullVisitor &vis) } void +StructExprStructBase::accept_vis (HIRExpressionVisitor &vis) +{ + vis.visit (*this); +} + +void CallExpr::accept_vis (HIRFullVisitor &vis) { vis.visit (*this); @@ -4100,18 +4145,6 @@ IfExprConseqElse::accept_vis (HIRFullVisitor &vis) } void -IfLetExpr::accept_vis (HIRFullVisitor &vis) -{ - vis.visit (*this); -} - -void -IfLetExprConseqElse::accept_vis (HIRFullVisitor &vis) -{ - vis.visit (*this); -} - -void MatchExpr::accept_vis (HIRFullVisitor &vis) { vis.visit (*this); @@ -4484,12 +4517,6 @@ ParenthesisedType::accept_vis (HIRFullVisitor &vis) } void -ImplTraitTypeOneBound::accept_vis (HIRFullVisitor &vis) -{ - vis.visit (*this); -} - -void TupleType::accept_vis (HIRFullVisitor &vis) { vis.visit (*this); @@ -4682,12 +4709,6 @@ ArrayType::accept_vis (HIRTypeVisitor &vis) } void -ImplTraitTypeOneBound::accept_vis (HIRTypeVisitor &vis) -{ - vis.visit (*this); -} - -void BareFunctionType::accept_vis (HIRTypeVisitor &vis) { vis.visit (*this); @@ -4862,18 +4883,6 @@ RangeFromToInclExpr::accept_vis (HIRExpressionVisitor &vis) } void -IfLetExprConseqElse::accept_vis (HIRExpressionVisitor &vis) -{ - vis.visit (*this); -} - -void -IfLetExpr::accept_vis (HIRExpressionVisitor &vis) -{ - vis.visit (*this); -} - -void IfExprConseqElse::accept_vis (HIRExpressionVisitor &vis) { vis.visit (*this); @@ -5161,20 +5170,5 @@ StaticItem::accept_vis (HIRVisItemVisitor &vis) vis.visit (*this); } -std::string -ConstGenericParam::as_string () const -{ - auto result = "ConstGenericParam: " + name + " : " + type->as_string (); - - if (default_expression) - result += " = " + default_expression->as_string (); - - return result; -} - -void -ConstGenericParam::accept_vis (HIRFullVisitor &) -{} - } // namespace HIR } // namespace Rust diff --git a/gcc/rust/hir/tree/rust-hir.h b/gcc/rust/hir/tree/rust-hir.h index d7245d4..ffab5ff 100644 --- a/gcc/rust/hir/tree/rust-hir.h +++ b/gcc/rust/hir/tree/rust-hir.h @@ -19,767 +19,24 @@ #ifndef RUST_HIR_BASE_H #define RUST_HIR_BASE_H -#include "rust-ast.h" #include "rust-system.h" +#include "rust-ast.h" +#include "rust-hir-visitable.h" +#include "rust-hir-attrs.h" + #include "rust-token.h" + #include "rust-location.h" + #include "rust-hir-map.h" #include "rust-diagnostics.h" +#include "rust-hir-bound.h" namespace Rust { + typedef int TupleIndex; namespace HIR { -// foward decl: ast visitor -class HIRFullVisitor; -class HIRStmtVisitor; -class HIRTraitItemVisitor; -class HIRExternalItemVisitor; -class HIRVisItemVisitor; -class HIRExpressionVisitor; -class HIRPatternVisitor; -class HIRImplVisitor; -class HIRTypeVisitor; - -class WithOuterAttrs -{ -protected: - AST::AttrVec outer_attrs; - -public: - AST::AttrVec &get_outer_attrs () { return outer_attrs; } - const AST::AttrVec &get_outer_attrs () const { return outer_attrs; } - - WithOuterAttrs (AST::AttrVec outer_attrs) - : outer_attrs (std::move (outer_attrs)){}; -}; - -class WithInnerAttrs -{ -protected: - AST::AttrVec inner_attrs; - -public: - AST::AttrVec get_inner_attrs () const { return inner_attrs; } - WithInnerAttrs (AST::AttrVec inner_attrs) - : inner_attrs (std::move (inner_attrs)){}; -}; - -class FullVisitable -{ -public: - virtual void accept_vis (HIRFullVisitor &vis) = 0; -}; - -// forward decl for use in token tree method -class Token; - -class Node -{ -public: - // Kind for downcasting various HIR nodes to other base classes when visiting - // them - enum BaseKind - { - /* class ExternalItem */ - EXTERNAL, - /* class TraitItem */ - TRAIT_ITEM, - /* class VisItem */ - VIS_ITEM, - /* class Item */ - ITEM, - /* class ImplItem */ - IMPL, - /* class Type */ - TYPE, - /* class Stmt */ - STMT, - /* class Expr */ - EXPR, - /* class Pattern */ - PATTERN, - }; - - /** - * Get the kind of HIR node we are dealing with. This is useful for - * downcasting to more precise types when necessary, i.e going from an `Item*` - * to a `VisItem*` - */ - virtual BaseKind get_hir_kind () = 0; -}; - -// A literal - value with a type. Used in LiteralExpr and LiteralPattern. -struct Literal -{ -public: - enum LitType - { - CHAR, - STRING, - BYTE, - BYTE_STRING, - INT, - FLOAT, - BOOL - }; - -private: - std::string value_as_string; - LitType type; - PrimitiveCoreType type_hint; - -public: - std::string as_string () const { return value_as_string; } - - LitType get_lit_type () const { return type; } - - PrimitiveCoreType get_type_hint () const { return type_hint; } - - Literal (std::string value_as_string, LitType type, - PrimitiveCoreType type_hint) - : value_as_string (std::move (value_as_string)), type (type), - type_hint (type_hint) - {} - - static Literal create_error () - { - return Literal ("", CHAR, PrimitiveCoreType::CORETYPE_UNKNOWN); - } - - void set_lit_type (LitType lt) { type = lt; } - - // Returns whether literal is in an invalid state. - bool is_error () const { return value_as_string == ""; } - - bool is_equal (Literal &other) - { - return value_as_string == other.value_as_string && type == other.type - && type_hint == other.type_hint; - } -}; - -/* Base statement abstract class. Note that most "statements" are not allowed in - * top-level module scope - only a subclass of statements called "items" are. */ -class Stmt : public Node, public FullVisitable -{ -public: - using FullVisitable::accept_vis; - - // Unique pointer custom clone function - std::unique_ptr<Stmt> clone_stmt () const - { - return std::unique_ptr<Stmt> (clone_stmt_impl ()); - } - - BaseKind get_hir_kind () override { return STMT; } - - virtual ~Stmt () {} - - virtual std::string as_string () const = 0; - - virtual void accept_vis (HIRStmtVisitor &vis) = 0; - - virtual location_t get_locus () const = 0; - - virtual bool is_unit_check_needed () const { return false; } - - const Analysis::NodeMapping &get_mappings () const { return mappings; } - - virtual bool is_item () const = 0; - -protected: - Stmt (Analysis::NodeMapping mappings) : mappings (std::move (mappings)) {} - - // Clone function implementation as pure virtual method - virtual Stmt *clone_stmt_impl () const = 0; - - Analysis::NodeMapping mappings; -}; - -// Rust "item" HIR node (declaration of top-level/module-level allowed stuff) -class Item : public Stmt, public WithOuterAttrs -{ - // TODO: should outer attrs be defined here or in each derived class? -public: - enum class ItemKind - { - Static, - Constant, - TypeAlias, - Function, - UseDeclaration, - ExternBlock, - ExternCrate, - Struct, - Union, - Enum, - EnumItem, // FIXME: ARTHUR: Do we need that? - Trait, - Impl, - Module, - }; - - virtual ItemKind get_item_kind () const = 0; - - // Unique pointer custom clone function - std::unique_ptr<Item> clone_item () const - { - return std::unique_ptr<Item> (clone_item_impl ()); - } - - BaseKind get_hir_kind () override { return ITEM; } - - std::string as_string () const override; - - /* Adds crate names to the vector passed by reference, if it can - * (polymorphism). */ - virtual void - add_crate_name (std::vector<std::string> &names ATTRIBUTE_UNUSED) const - {} - - bool is_item () const override final { return true; } - -protected: - // Constructor - Item (Analysis::NodeMapping mappings, - AST::AttrVec outer_attribs = AST::AttrVec ()) - : Stmt (std::move (mappings)), WithOuterAttrs (std::move (outer_attribs)) - {} - - // Clone function implementation as pure virtual method - virtual Item *clone_item_impl () const = 0; - - /* Save having to specify two clone methods in derived classes by making - * statement clone return item clone. Hopefully won't affect performance too - * much. */ - Item *clone_stmt_impl () const override { return clone_item_impl (); } -}; - -// forward decl of ExprWithoutBlock -class ExprWithoutBlock; - -// Base expression HIR node - abstract -class Expr : public Node, virtual public FullVisitable -{ -public: - using FullVisitable::accept_vis; - -protected: - AST::AttrVec outer_attrs; - Analysis::NodeMapping mappings; - -public: - enum BlockType - { - WITH_BLOCK, - WITHOUT_BLOCK, - }; - - enum ExprType - { - Lit, - Operator, - Grouped, - Array, - ArrayIndex, - Tuple, - TupleIdx, - Struct, - Call, - MethodCall, - FieldAccess, - Closure, - Block, - Continue, - Break, - Range, - Return, - UnsafeBlock, - BaseLoop, - If, - IfLet, - Match, - Await, - AsyncBlock, - Path, - InlineAsm, - }; - - BaseKind get_hir_kind () override final { return EXPR; } - - const AST::AttrVec &get_outer_attrs () const { return outer_attrs; } - - // Unique pointer custom clone function - std::unique_ptr<Expr> clone_expr () const - { - return std::unique_ptr<Expr> (clone_expr_impl ()); - } - - // TODO: make pure virtual if move out outer attributes to derived classes - virtual std::string as_string () const; - - virtual ~Expr () {} - - virtual location_t get_locus () const = 0; - - const Analysis::NodeMapping &get_mappings () const { return mappings; } - - // Clone function implementation as pure virtual method - virtual Expr *clone_expr_impl () const = 0; - - virtual BlockType get_block_expr_type () const = 0; - - virtual ExprType get_expression_type () const = 0; - - virtual void accept_vis (HIRExpressionVisitor &vis) = 0; - -protected: - // Constructor - Expr (Analysis::NodeMapping mappings, - AST::AttrVec outer_attribs = AST::AttrVec ()) - : outer_attrs (std::move (outer_attribs)), mappings (std::move (mappings)) - {} - - // TODO: think of less hacky way to implement this kind of thing - // Sets outer attributes. - void set_outer_attrs (AST::AttrVec outer_attrs_to_set) - { - outer_attrs = std::move (outer_attrs_to_set); - } -}; - -// HIR node for an expression without an accompanying block - abstract -class ExprWithoutBlock : public Expr -{ -protected: - // Constructor - ExprWithoutBlock (Analysis::NodeMapping mappings, - AST::AttrVec outer_attribs = AST::AttrVec ()) - : Expr (std::move (mappings), std::move (outer_attribs)) - {} - - // pure virtual clone implementation - virtual ExprWithoutBlock *clone_expr_without_block_impl () const = 0; - - /* Save having to specify two clone methods in derived classes by making expr - * clone return exprwithoutblock clone. Hopefully won't affect performance too - * much. */ - ExprWithoutBlock *clone_expr_impl () const override - { - return clone_expr_without_block_impl (); - } - -public: - // Unique pointer custom clone function - std::unique_ptr<ExprWithoutBlock> clone_expr_without_block () const - { - return std::unique_ptr<ExprWithoutBlock> (clone_expr_without_block_impl ()); - } - - BlockType get_block_expr_type () const final override - { - return BlockType::WITHOUT_BLOCK; - }; -}; - -// Pattern base HIR node -class Pattern : public Node, virtual public FullVisitable -{ -public: - using FullVisitable::accept_vis; - - enum PatternType - { - PATH, - LITERAL, - IDENTIFIER, - WILDCARD, - RANGE, - REFERENCE, - STRUCT, - TUPLE_STRUCT, - TUPLE, - GROUPED, - SLICE, - ALT - }; - - BaseKind get_hir_kind () override final { return PATTERN; } - - // Unique pointer custom clone function - std::unique_ptr<Pattern> clone_pattern () const - { - return std::unique_ptr<Pattern> (clone_pattern_impl ()); - } - - // possible virtual methods: is_refutable() - - virtual ~Pattern () {} - - virtual std::string as_string () const = 0; - - virtual void accept_vis (HIRPatternVisitor &vis) = 0; - - virtual const Analysis::NodeMapping &get_mappings () const = 0; - - virtual location_t get_locus () const = 0; - - virtual PatternType get_pattern_type () const = 0; - -protected: - // Clone pattern implementation as pure virtual method - virtual Pattern *clone_pattern_impl () const = 0; -}; - -// forward decl for Type -class TraitBound; - -// Base class for types as represented in HIR - abstract -class Type : public Node, public FullVisitable -{ -public: - using FullVisitable::accept_vis; - // Unique pointer custom clone function - std::unique_ptr<Type> clone_type () const - { - return std::unique_ptr<Type> (clone_type_impl ()); - } - - // virtual destructor - virtual ~Type () {} - - BaseKind get_hir_kind () override final { return TYPE; } - - virtual std::string as_string () const = 0; - - /* HACK: convert to trait bound. Virtual method overriden by classes that - * enable this. */ - virtual TraitBound *to_trait_bound (bool in_parens ATTRIBUTE_UNUSED) const - { - return nullptr; - } - /* as pointer, shouldn't require definition beforehand, only forward - * declaration. */ - - virtual void accept_vis (HIRTypeVisitor &vis) = 0; - - virtual Analysis::NodeMapping get_mappings () const { return mappings; } - virtual location_t get_locus () const { return locus; } - -protected: - Type (Analysis::NodeMapping mappings, location_t locus) - : mappings (mappings), locus (locus) - {} - - // Clone function implementation as pure virtual method - virtual Type *clone_type_impl () const = 0; - - Analysis::NodeMapping mappings; - location_t locus; -}; - -// A type without parentheses? - abstract -class TypeNoBounds : public Type -{ -public: - // Unique pointer custom clone function - std::unique_ptr<TypeNoBounds> clone_type_no_bounds () const - { - return std::unique_ptr<TypeNoBounds> (clone_type_no_bounds_impl ()); - } - -protected: - TypeNoBounds (Analysis::NodeMapping mappings, location_t locus) - : Type (mappings, locus) - {} - - // Clone function implementation as pure virtual method - virtual TypeNoBounds *clone_type_no_bounds_impl () const = 0; - - /* Save having to specify two clone methods in derived classes by making type - * clone return typenobounds clone. Hopefully won't affect performance too - * much. */ - TypeNoBounds *clone_type_impl () const override - { - return clone_type_no_bounds_impl (); - } -}; - -/* Abstract base class representing a type param bound - Lifetime and TraitBound - * extends it */ -class TypeParamBound : public FullVisitable -{ -public: - using FullVisitable::accept_vis; - enum BoundType - { - LIFETIME, - TRAITBOUND - }; - - virtual ~TypeParamBound () {} - - // Unique pointer custom clone function - std::unique_ptr<TypeParamBound> clone_type_param_bound () const - { - return std::unique_ptr<TypeParamBound> (clone_type_param_bound_impl ()); - } - - virtual std::string as_string () const = 0; - - virtual Analysis::NodeMapping get_mappings () const = 0; - - virtual location_t get_locus () const = 0; - - virtual BoundType get_bound_type () const = 0; - -protected: - // Clone function implementation as pure virtual method - virtual TypeParamBound *clone_type_param_bound_impl () const = 0; -}; - -// Represents a lifetime (and is also a kind of type param bound) -class Lifetime : public TypeParamBound -{ -private: - AST::Lifetime::LifetimeType lifetime_type; - std::string lifetime_name; - location_t locus; - Analysis::NodeMapping mappings; - -public: - // Constructor - Lifetime (Analysis::NodeMapping mapping, AST::Lifetime::LifetimeType type, - std::string name, location_t locus) - : lifetime_type (type), lifetime_name (std::move (name)), locus (locus), - mappings (mapping) - {} - - // Returns true if the lifetime is in an error state. - bool is_error () const - { - return lifetime_type == AST::Lifetime::LifetimeType::NAMED - && lifetime_name.empty (); - } - - static Lifetime error () - { - return Lifetime (Analysis::NodeMapping::get_error (), - AST::Lifetime::LifetimeType::NAMED, "", UNDEF_LOCATION); - } - - std::string as_string () const override; - - void accept_vis (HIRFullVisitor &vis) override; - - WARN_UNUSED_RESULT const std::string &get_name () const - { - return lifetime_name; - } - - AST::Lifetime::LifetimeType get_lifetime_type () const - { - return lifetime_type; - } - - location_t get_locus () const override final { return locus; } - - Analysis::NodeMapping get_mappings () const override final - { - return mappings; - } - - BoundType get_bound_type () const final override { return LIFETIME; } - -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - Lifetime *clone_type_param_bound_impl () const override - { - return new Lifetime (*this); - } -}; - -/* Base generic parameter in HIR. Abstract - can be represented by a Lifetime or - * Type param */ -class GenericParam : public FullVisitable -{ -public: - using FullVisitable::accept_vis; - - virtual ~GenericParam () {} - - enum class GenericKind - { - TYPE, - LIFETIME, - CONST, - }; - - // Unique pointer custom clone function - std::unique_ptr<GenericParam> clone_generic_param () const - { - return std::unique_ptr<GenericParam> (clone_generic_param_impl ()); - } - - virtual std::string as_string () const = 0; - - virtual location_t get_locus () const = 0; - - Analysis::NodeMapping get_mappings () const { return mappings; } - - enum GenericKind get_kind () const { return kind; } - -protected: - // Clone function implementation as pure virtual method - virtual GenericParam *clone_generic_param_impl () const = 0; - - Analysis::NodeMapping mappings; - - enum GenericKind kind; - - GenericParam (Analysis::NodeMapping mapping, - enum GenericKind kind = GenericKind::TYPE) - : mappings (mapping), kind (kind) - {} -}; - -// A lifetime generic parameter (as opposed to a type generic parameter) -class LifetimeParam : public GenericParam -{ - Lifetime lifetime; - - // bool has_lifetime_bounds; - // LifetimeBounds lifetime_bounds; - std::vector<Lifetime> lifetime_bounds; // inlined LifetimeBounds - - // bool has_outer_attribute; - // std::unique_ptr<Attribute> outer_attr; - AST::Attribute outer_attr; - - location_t locus; - -public: - Lifetime get_lifetime () { return lifetime; } - - // Returns whether the lifetime param has any lifetime bounds. - bool has_lifetime_bounds () const { return !lifetime_bounds.empty (); } - - std::vector<Lifetime> &get_lifetime_bounds () { return lifetime_bounds; } - - // Returns whether the lifetime param has an outer attribute. - bool has_outer_attribute () const { return !outer_attr.is_empty (); } - - // Returns whether the lifetime param is in an error state. - bool is_error () const { return lifetime.is_error (); } - - // Constructor - LifetimeParam (Analysis::NodeMapping mappings, Lifetime lifetime, - location_t locus = UNDEF_LOCATION, - std::vector<Lifetime> lifetime_bounds - = std::vector<Lifetime> (), - AST::Attribute outer_attr = AST::Attribute::create_empty ()) - : GenericParam (mappings, GenericKind::LIFETIME), - lifetime (std::move (lifetime)), - lifetime_bounds (std::move (lifetime_bounds)), - outer_attr (std::move (outer_attr)), locus (locus) - {} - - // TODO: remove copy and assignment operator definitions - not required - - // Copy constructor with clone - LifetimeParam (LifetimeParam const &other) - : GenericParam (other.mappings, GenericKind::LIFETIME), - lifetime (other.lifetime), lifetime_bounds (other.lifetime_bounds), - outer_attr (other.outer_attr), locus (other.locus) - {} - - // Overloaded assignment operator to clone attribute - LifetimeParam &operator= (LifetimeParam const &other) - { - lifetime = other.lifetime; - lifetime_bounds = other.lifetime_bounds; - outer_attr = other.outer_attr; - locus = other.locus; - mappings = other.mappings; - - return *this; - } - - // move constructors - LifetimeParam (LifetimeParam &&other) = default; - LifetimeParam &operator= (LifetimeParam &&other) = default; - - std::string as_string () const override; - - void accept_vis (HIRFullVisitor &vis) override; - - location_t get_locus () const override final { return locus; } - -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - LifetimeParam *clone_generic_param_impl () const override - { - return new LifetimeParam (*this); - } -}; - -class ConstGenericParam : public GenericParam -{ -public: - ConstGenericParam (std::string name, std::unique_ptr<Type> type, - std::unique_ptr<Expr> default_expression, - Analysis::NodeMapping mapping, location_t locus) - : GenericParam (mapping, GenericKind::CONST), name (std::move (name)), - type (std::move (type)), - default_expression (std::move (default_expression)), locus (locus) - {} - - ConstGenericParam (const ConstGenericParam &other) : GenericParam (other) - { - name = other.name; - locus = other.locus; - - if (other.type) - type = other.type->clone_type (); - if (other.default_expression) - default_expression = other.default_expression->clone_expr (); - } - - std::string as_string () const override final; - - void accept_vis (HIRFullVisitor &vis) override final; - - location_t get_locus () const override final { return locus; }; - - bool has_default_expression () { return default_expression != nullptr; } - - std::string get_name () { return name; } - std::unique_ptr<Type> &get_type () { return type; } - std::unique_ptr<Expr> &get_default_expression () - { - return default_expression; - } - -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - ConstGenericParam *clone_generic_param_impl () const override - { - return new ConstGenericParam (*this); - } - -private: - std::string name; - std::unique_ptr<Type> type; - - /* Optional - can be a null pointer if there is no default expression */ - std::unique_ptr<Expr> default_expression; - - location_t locus; -}; // Item used in trait declarations - abstract base class class TraitItem : public Node, public FullVisitable @@ -880,34 +137,15 @@ class Crate : public WithInnerAttrs public: // Constructor Crate (std::vector<std::unique_ptr<Item>> items, AST::AttrVec inner_attrs, - Analysis::NodeMapping mappings) - : WithInnerAttrs (std::move (inner_attrs)), items (std::move (items)), - mappings (mappings) - {} + Analysis::NodeMapping mappings); // Copy constructor with vector clone - Crate (Crate const &other) - : WithInnerAttrs (other.inner_attrs), mappings (other.mappings) - { - items.reserve (other.items.size ()); - for (const auto &e : other.items) - items.push_back (e->clone_item ()); - } + Crate (Crate const &other); ~Crate () = default; // Overloaded assignment operator with vector clone - Crate &operator= (Crate const &other) - { - inner_attrs = other.inner_attrs; - mappings = other.mappings; - - items.reserve (other.items.size ()); - for (const auto &e : other.items) - items.push_back (e->clone_item ()); - - return *this; - } + Crate &operator= (Crate const &other); // Move constructors Crate (Crate &&other) = default; @@ -920,27 +158,6 @@ public: std::vector<std::unique_ptr<Item>> &get_items () { return items; } }; -// Base path expression HIR node - abstract -class PathExpr : public ExprWithoutBlock -{ -protected: - PathExpr (Analysis::NodeMapping mappings, AST::AttrVec outer_attribs) - : ExprWithoutBlock (std::move (mappings), std::move (outer_attribs)) - {} - -public: - /* Replaces the outer attributes of this path expression with the given outer - * attributes. */ - void replace_outer_attrs (AST::AttrVec outer_attrs) - { - set_outer_attrs (std::move (outer_attrs)); - } - - ExprType get_expression_type () const final override - { - return ExprType::Path; - } -}; } // namespace HIR } // namespace Rust diff --git a/gcc/rust/lang.opt b/gcc/rust/lang.opt index ae601eb..9cdbce2 100644 --- a/gcc/rust/lang.opt +++ b/gcc/rust/lang.opt @@ -212,4 +212,21 @@ frust-borrowcheck Rust Var(flag_borrowcheck) Use the WIP borrow checker. +frust-panic= +Rust Joined RejectNegative Enum(frust_panic) Var(flag_rust_panic) +-frust-edition=[unwind|abort] Panic strategy to compile crate with + +Enum +Name(frust_panic) Type(int) UnknownError(unknown panic strategy %qs) + +EnumValue +Enum(frust_panic) String(unwind) Value(0) + +EnumValue +Enum(frust_panic) String(abort) Value(1) + +frust-overflow-checks +Rust Var(flag_overflow_checks) Init(1) +Enable the overflow checks in code generation + ; This comment is to ensure we retain the blank line above. diff --git a/gcc/rust/lex/rust-lex.cc b/gcc/rust/lex/rust-lex.cc index f4b8861..b143e70 100644 --- a/gcc/rust/lex/rust-lex.cc +++ b/gcc/rust/lex/rust-lex.cc @@ -21,7 +21,7 @@ #include "rust-lex.h" #include "rust-diagnostics.h" #include "rust-linemap.h" -#include "rust-session-manager.h" +#include "rust-edition.h" #include "safe-ctype.h" #include "cpplib.h" #include "rust-keyword-values.h" @@ -277,9 +277,7 @@ Lexer::classify_keyword (const std::string &str) // https://doc.rust-lang.org/reference/keywords.html#reserved-keywords // `try` is not a reserved keyword before 2018 - if (Session::get_instance ().options.get_edition () - == CompileOptions::Edition::E2015 - && id == TRY) + if (get_rust_edition () == Edition::E2015 && id == TRY) return IDENTIFIER; return id; @@ -589,7 +587,8 @@ Lexer::build_token () if (current_char.is_eof ()) { rust_error_at ( - loc, "unexpected EOF while looking for end of comment"); + loc, ErrorCode::E0758, + "unexpected EOF while looking for end of comment"); break; } str += current_char; @@ -644,7 +643,8 @@ Lexer::build_token () if (current_char.is_eof ()) { rust_error_at ( - loc, "unexpected EOF while looking for end of comment"); + loc, ErrorCode::E0758, + "unexpected EOF while looking for end of comment"); break; } @@ -708,7 +708,8 @@ Lexer::build_token () if (current_char.is_eof ()) { rust_error_at ( - loc, "unexpected EOF while looking for end of comment"); + loc, ErrorCode::E0758, + "unexpected EOF while looking for end of comment"); break; } diff --git a/gcc/rust/lex/rust-lex.h b/gcc/rust/lex/rust-lex.h index 8265ca8..10293e0 100644 --- a/gcc/rust/lex/rust-lex.h +++ b/gcc/rust/lex/rust-lex.h @@ -115,14 +115,15 @@ private: // Request new Location for current column in line_table location_t get_current_location (); - // Skips the current input char. + // Skips the current input character. void skip_input (); - // Advances current input char to n + 1 chars ahead of current position. + // Advances current input character to n + 1 characters ahead of current + // position. void skip_input (int n); - // Peeks the current char. + // Peeks the current character. Codepoint peek_input (); - // Returns char n bytes ahead of current position. + // Returns character n characters ahead of current position. Codepoint peek_input (int n); // Classifies keyword (i.e. gets id for keyword). diff --git a/gcc/rust/lex/rust-token.h b/gcc/rust/lex/rust-token.h index aa2f308..c683ecd 100644 --- a/gcc/rust/lex/rust-token.h +++ b/gcc/rust/lex/rust-token.h @@ -21,7 +21,6 @@ #include "rust-system.h" #include "rust-linemap.h" -#include "rust-make-unique.h" #include "rust-unicode.h" namespace Rust { @@ -268,7 +267,7 @@ private: : token_id (token_id), locus (location), type_hint (CORETYPE_UNKNOWN) { // Normalize identifier tokens - str = Rust::make_unique<std::string> ( + str = std::make_unique<std::string> ( nfc_normalize_token_string (location, token_id, paramStr)); } @@ -285,7 +284,7 @@ private: : token_id (token_id), locus (location), type_hint (CORETYPE_UNKNOWN) { // Normalize identifier tokens - str = Rust::make_unique<std::string> ( + str = std::make_unique<std::string> ( nfc_normalize_token_string (location, token_id, paramCodepoint.as_string ())); } @@ -296,7 +295,7 @@ private: : token_id (token_id), locus (location), type_hint (parType) { // Normalize identifier tokens - str = Rust::make_unique<std::string> ( + str = std::make_unique<std::string> ( nfc_normalize_token_string (location, token_id, paramStr)); } diff --git a/gcc/rust/metadata/rust-export-metadata.cc b/gcc/rust/metadata/rust-export-metadata.cc index 79c5f30..771bec6 100644 --- a/gcc/rust/metadata/rust-export-metadata.cc +++ b/gcc/rust/metadata/rust-export-metadata.cc @@ -234,7 +234,7 @@ PublicInterface::write_to_path (const std::string &path) const { // validate path contains correct extension const std::string expected_file_name = expected_metadata_filename (); - const char *path_base_name = basename (path.c_str ()); + const char *path_base_name = lbasename (path.c_str ()); if (strcmp (path_base_name, expected_file_name.c_str ()) != 0) { rust_error_at (UNDEF_LOCATION, diff --git a/gcc/rust/metadata/rust-import-archive.cc b/gcc/rust/metadata/rust-import-archive.cc index 6c392b0..cf24607 100644 --- a/gcc/rust/metadata/rust-import-archive.cc +++ b/gcc/rust/metadata/rust-import-archive.cc @@ -7,7 +7,6 @@ #include "rust-system.h" #include "rust-diagnostics.h" #include "rust-imports.h" -#include "rust-make-unique.h" #ifndef O_BINARY #define O_BINARY 0 @@ -844,7 +843,7 @@ Import::find_archive_export_data (const std::string &filename, int fd, if (!afile.initialize ()) return nullptr; - auto ret = Rust::make_unique<Stream_concatenate> (); + auto ret = std::make_unique<Stream_concatenate> (); bool any_data = false; bool any_members = false; @@ -872,7 +871,7 @@ Import::find_archive_export_data (const std::string &filename, int fd, if (!any_members) { // It's normal to have an empty archive file when using gobuild. - return Rust::make_unique<Stream_from_string> (""); + return std::make_unique<Stream_from_string> (""); } if (!any_data) diff --git a/gcc/rust/metadata/rust-imports.cc b/gcc/rust/metadata/rust-imports.cc index f2ab105..8d5c381 100644 --- a/gcc/rust/metadata/rust-imports.cc +++ b/gcc/rust/metadata/rust-imports.cc @@ -21,7 +21,6 @@ #include "rust-imports.h" #include "rust-object-export.h" #include "rust-export-metadata.h" -#include "rust-make-unique.h" #ifndef O_BINARY #define O_BINARY 0 @@ -259,7 +258,7 @@ Import::find_export_data (const std::string &filename, int fd, // if (memcmp (buf, Metadata::kMagicHeader, sizeof (Metadata::kMagicHeader)) == 0) - return Rust::make_unique<Stream_from_file> (fd); + return std::make_unique<Stream_from_file> (fd); // See if we can read this as an archive. if (Import::is_archive_magic (buf)) @@ -291,7 +290,7 @@ Import::find_object_export_data (const std::string &filename, int fd, if (buf == nullptr) return nullptr; - return Rust::make_unique<Stream_from_buffer> (buf, len); + return std::make_unique<Stream_from_buffer> (buf, len); } // Class Import. diff --git a/gcc/rust/parse/rust-parse-impl.h b/gcc/rust/parse/rust-parse-impl.h index d5383ad..9dda231 100644 --- a/gcc/rust/parse/rust-parse-impl.h +++ b/gcc/rust/parse/rust-parse-impl.h @@ -29,11 +29,10 @@ #include "rust-token.h" #define INCLUDE_ALGORITHM #include "rust-diagnostics.h" -#include "rust-make-unique.h" #include "rust-dir-owner.h" #include "rust-attribute-values.h" #include "rust-keyword-values.h" -#include "rust-session-manager.h" +#include "rust-edition.h" #include "optional.h" @@ -1454,8 +1453,7 @@ Parser<ManagedTokenSource>::parse_async_item (AST::Visibility vis, auto offset = (lexer.peek_token ()->get_id () == CONST) ? 1 : 0; const_TokenPtr t = lexer.peek_token (offset); - if (Session::get_instance ().options.get_edition () - == CompileOptions::Edition::E2015) + if (get_rust_edition () == Edition::E2015) { add_error (Error (t->get_locus (), ErrorCode::E0670, "%<async fn%> is not permitted in Rust 2015")); @@ -3104,7 +3102,7 @@ Parser<ManagedTokenSource>::parse_generic_param (EndTokenPred is_end_token) { case LIFETIME: { auto lifetime = parse_lifetime (false); - if (lifetime.is_error ()) + if (!lifetime) { rust_error_at ( token->get_locus (), @@ -3124,7 +3122,7 @@ Parser<ManagedTokenSource>::parse_generic_param (EndTokenPred is_end_token) } param = std::unique_ptr<AST::LifetimeParam> (new AST::LifetimeParam ( - std::move (lifetime), std::move (lifetime_bounds), + std::move (lifetime.value ()), std::move (lifetime_bounds), std::move (outer_attrs), token->get_locus ())); break; } @@ -3176,24 +3174,28 @@ Parser<ManagedTokenSource>::parse_generic_param (EndTokenPred is_end_token) return nullptr; // optional default value - auto default_expr = AST::GenericArg::create_error (); + tl::optional<AST::GenericArg> default_expr = tl::nullopt; if (lexer.peek_token ()->get_id () == EQUAL) { lexer.skip_token (); auto tok = lexer.peek_token (); default_expr = parse_generic_arg (); - if (default_expr.is_error ()) - rust_error_at (tok->get_locus (), - "invalid token for start of default value for " - "const generic parameter: expected %<block%>, " - "%<identifier%> or %<literal%>, got %qs", - token_id_to_str (tok->get_id ())); + if (!default_expr) + { + rust_error_at (tok->get_locus (), + "invalid token for start of default value for " + "const generic parameter: expected %<block%>, " + "%<identifier%> or %<literal%>, got %qs", + token_id_to_str (tok->get_id ())); + return nullptr; + } // At this point, we *know* that we are parsing a const // expression - if (default_expr.get_kind () == AST::GenericArg::Kind::Either) - default_expr = default_expr.disambiguate_to_const (); + if (default_expr.value ().get_kind () + == AST::GenericArg::Kind::Either) + default_expr = default_expr.value ().disambiguate_to_const (); } param = std::unique_ptr<AST::ConstGenericParam> ( @@ -3278,16 +3280,16 @@ Parser<ManagedTokenSource>::parse_lifetime_params () while (lexer.peek_token ()->get_id () != END_OF_FILE) { - AST::LifetimeParam lifetime_param = parse_lifetime_param (); + auto lifetime_param = parse_lifetime_param (); - if (lifetime_param.is_error ()) + if (!lifetime_param) { // can't treat as error as only way to get out with trailing comma break; } lifetime_params.push_back (std::unique_ptr<AST::LifetimeParam> ( - new AST::LifetimeParam (std::move (lifetime_param)))); + new AST::LifetimeParam (std::move (lifetime_param.value ())))); if (lexer.peek_token ()->get_id () != COMMA) break; @@ -3313,9 +3315,9 @@ Parser<ManagedTokenSource>::parse_lifetime_params (EndTokenPred is_end_token) // if end_token is not specified, it defaults to EOF, so should work fine while (!is_end_token (lexer.peek_token ()->get_id ())) { - AST::LifetimeParam lifetime_param = parse_lifetime_param (); + auto lifetime_param = parse_lifetime_param (); - if (lifetime_param.is_error ()) + if (!lifetime_param) { /* TODO: is it worth throwing away all lifetime params just because * one failed? */ @@ -3353,9 +3355,9 @@ Parser<ManagedTokenSource>::parse_lifetime_params_objs () // bad control structure as end token cannot be guaranteed while (true) { - AST::LifetimeParam lifetime_param = parse_lifetime_param (); + auto lifetime_param = parse_lifetime_param (); - if (lifetime_param.is_error ()) + if (!lifetime_param) { // not an error as only way to exit if trailing comma break; @@ -3388,9 +3390,9 @@ Parser<ManagedTokenSource>::parse_lifetime_params_objs ( while (!is_end_token (lexer.peek_token ()->get_id ())) { - AST::LifetimeParam lifetime_param = parse_lifetime_param (); + auto lifetime_param = parse_lifetime_param (); - if (lifetime_param.is_error ()) + if (!lifetime_param) { /* TODO: is it worth throwing away all lifetime params just because * one failed? */ @@ -3401,7 +3403,7 @@ Parser<ManagedTokenSource>::parse_lifetime_params_objs ( return {}; } - lifetime_params.push_back (std::move (lifetime_param)); + lifetime_params.push_back (std::move (lifetime_param.value ())); if (lexer.peek_token ()->get_id () != COMMA) break; @@ -3460,7 +3462,7 @@ Parser<ManagedTokenSource>::parse_non_ptr_sequence ( /* Parses a single lifetime generic parameter (not including comma). */ template <typename ManagedTokenSource> -AST::LifetimeParam +tl::expected<AST::LifetimeParam, ParseLifetimeParamError> Parser<ManagedTokenSource>::parse_lifetime_param () { // parse outer attributes, which are optional and may not exist @@ -3470,8 +3472,8 @@ Parser<ManagedTokenSource>::parse_lifetime_param () const_TokenPtr lifetime_tok = lexer.peek_token (); if (lifetime_tok->get_id () != LIFETIME) { - // if lifetime is missing, must not be a lifetime param, so return null - return AST::LifetimeParam::create_error (); + // if lifetime is missing, must not be a lifetime param, so return error + return tl::make_unexpected<ParseLifetimeParamError> ({}); } lexer.skip_token (); AST::Lifetime lifetime (AST::Lifetime::NAMED, lifetime_tok->get_str (), @@ -3683,7 +3685,7 @@ Parser<ManagedTokenSource>::parse_function_param () if (lexer.peek_token ()->get_id () == ELLIPSIS) // Unnamed variadic { lexer.skip_token (); // Skip ellipsis - return Rust::make_unique<AST::VariadicParam> ( + return std::make_unique<AST::VariadicParam> ( AST::VariadicParam (std::move (outer_attrs), locus)); } @@ -3705,7 +3707,7 @@ Parser<ManagedTokenSource>::parse_function_param () if (lexer.peek_token ()->get_id () == ELLIPSIS) // Named variadic { lexer.skip_token (); // Skip ellipsis - return Rust::make_unique<AST::VariadicParam> ( + return std::make_unique<AST::VariadicParam> ( AST::VariadicParam (std::move (param_pattern), std::move (outer_attrs), locus)); } @@ -3716,7 +3718,7 @@ Parser<ManagedTokenSource>::parse_function_param () { return nullptr; } - return Rust::make_unique<AST::FunctionParam> ( + return std::make_unique<AST::FunctionParam> ( AST::FunctionParam (std::move (param_pattern), std::move (param_type), std::move (outer_attrs), locus)); } @@ -3817,12 +3819,13 @@ template <typename ManagedTokenSource> std::unique_ptr<AST::LifetimeWhereClauseItem> Parser<ManagedTokenSource>::parse_lifetime_where_clause_item () { - AST::Lifetime lifetime = parse_lifetime (false); - if (lifetime.is_error ()) + auto parsed_lifetime = parse_lifetime (false); + if (!parsed_lifetime) { // TODO: error here? return nullptr; } + auto lifetime = parsed_lifetime.value (); if (!skip_token (COLON)) { @@ -4015,7 +4018,7 @@ Parser<ManagedTokenSource>::parse_type_param_bound () { case LIFETIME: return std::unique_ptr<AST::Lifetime> ( - new AST::Lifetime (parse_lifetime (false))); + new AST::Lifetime (parse_lifetime (false).value ())); case LEFT_PAREN: case QUESTION_MARK: case FOR: @@ -4088,13 +4091,13 @@ Parser<ManagedTokenSource>::parse_lifetime_bounds () while (true) { - AST::Lifetime lifetime = parse_lifetime (false); + auto lifetime = parse_lifetime (false); // quick exit for parsing failure - if (lifetime.is_error ()) + if (!lifetime) break; - lifetime_bounds.push_back (std::move (lifetime)); + lifetime_bounds.push_back (std::move (lifetime.value ())); /* plus is maybe not allowed at end - spec defines it weirdly, so * assuming allowed at end */ @@ -4118,9 +4121,9 @@ Parser<ManagedTokenSource>::parse_lifetime_bounds (EndTokenPred is_end_token) while (!is_end_token (lexer.peek_token ()->get_id ())) { - AST::Lifetime lifetime = parse_lifetime (false); + auto lifetime = parse_lifetime (false); - if (lifetime.is_error ()) + if (!lifetime) { /* TODO: is it worth throwing away all lifetime bound info just * because one failed? */ @@ -4131,7 +4134,7 @@ Parser<ManagedTokenSource>::parse_lifetime_bounds (EndTokenPred is_end_token) return {}; } - lifetime_bounds.push_back (std::move (lifetime)); + lifetime_bounds.push_back (std::move (lifetime.value ())); /* plus is maybe not allowed at end - spec defines it weirdly, so * assuming allowed at end */ @@ -4148,14 +4151,20 @@ Parser<ManagedTokenSource>::parse_lifetime_bounds (EndTokenPred is_end_token) /* Parses a lifetime token (named, 'static, or '_). Also handles lifetime not * existing. */ template <typename ManagedTokenSource> -AST::Lifetime +tl::expected<AST::Lifetime, ParseLifetimeError> Parser<ManagedTokenSource>::parse_lifetime (bool allow_elided) { const_TokenPtr lifetime_tok = lexer.peek_token (); if (lifetime_tok->get_id () != LIFETIME) { - return (allow_elided) ? AST::Lifetime::elided () - : AST::Lifetime::error (); + if (allow_elided) + { + return AST::Lifetime::elided (); + } + else + { + return tl::make_unexpected<ParseLifetimeError> ({}); + } } lexer.skip_token (); @@ -5937,106 +5946,6 @@ Parser<ManagedTokenSource>::parse_extern_block (AST::Visibility vis, std::move (outer_attrs), locus)); } -template <typename ManagedTokenSource> -AST::NamedFunctionParam -Parser<ManagedTokenSource>::parse_named_function_param () -{ - AST::AttrVec outer_attrs = parse_outer_attributes (); - location_t locus = lexer.peek_token ()->get_locus (); - - if (lexer.peek_token ()->get_id () == ELLIPSIS) // Unnamed variadic - { - lexer.skip_token (); // Skip ellipsis - return AST::NamedFunctionParam (std::move (outer_attrs), locus); - } - - // parse identifier/_ - std::string name; - - const_TokenPtr t = lexer.peek_token (); - location_t name_location = t->get_locus (); - switch (t->get_id ()) - { - case IDENTIFIER: - name = t->get_str (); - lexer.skip_token (); - break; - case UNDERSCORE: - name = "_"; - lexer.skip_token (); - break; - default: - // this is not a function param, but not necessarily an error - return AST::NamedFunctionParam::create_error (); - } - - if (!skip_token (COLON)) - { - // skip after somewhere? - return AST::NamedFunctionParam::create_error (); - } - - if (lexer.peek_token ()->get_id () == ELLIPSIS) // Named variadic - { - lexer.skip_token (); // Skip ellipsis - return AST::NamedFunctionParam (std::move (name), std::move (outer_attrs), - locus); - } - - // parse (required) type - std::unique_ptr<AST::Type> param_type = parse_type (); - if (param_type == nullptr) - { - Error error ( - lexer.peek_token ()->get_locus (), - "could not parse param type in extern block function declaration"); - add_error (std::move (error)); - - skip_after_semicolon (); - return AST::NamedFunctionParam::create_error (); - } - - return AST::NamedFunctionParam (std::move (name), std::move (param_type), - std::move (outer_attrs), name_location); -} - -template <typename ManagedTokenSource> -template <typename EndTokenPred> -std::vector<AST::NamedFunctionParam> -Parser<ManagedTokenSource>::parse_named_function_params ( - EndTokenPred is_end_token) -{ - std::vector<AST::NamedFunctionParam> params; - if (is_end_token (lexer.peek_token ()->get_id ())) - return params; - - auto initial_param = parse_named_function_param (); - if (initial_param.is_error ()) - return params; - - params.push_back (std::move (initial_param)); - auto t = lexer.peek_token (); - while (t->get_id () == COMMA) - { - lexer.skip_token (); - if (is_end_token (lexer.peek_token ()->get_id ())) - break; - - auto param = parse_named_function_param (); - if (param.is_error ()) - { - Error error (lexer.peek_token ()->get_locus (), - "failed to parse param in c function params"); - add_error (error); - return std::vector<AST::NamedFunctionParam> (); - } - params.push_back (std::move (param)); - t = lexer.peek_token (); - } - params.shrink_to_fit (); - return params; -} - // Parses a single extern block item (static or function declaration). template <typename ManagedTokenSource> std::unique_ptr<AST::ExternalItem> @@ -6265,6 +6174,10 @@ Parser<ManagedTokenSource>::parse_let_stmt (AST::AttrVec outer_attrs, } } + tl::optional<std::unique_ptr<AST::Expr>> else_expr = tl::nullopt; + if (maybe_skip_token (ELSE)) + else_expr = parse_block_expr (); + if (restrictions.consume_semi) { // `stmt` macro variables are parsed without a semicolon, but should be @@ -6279,7 +6192,7 @@ Parser<ManagedTokenSource>::parse_let_stmt (AST::AttrVec outer_attrs, return std::unique_ptr<AST::LetStmt> ( new AST::LetStmt (std::move (pattern), std::move (expr), std::move (type), - std::move (outer_attrs), locus)); + std::move (else_expr), std::move (outer_attrs), locus)); } // Parses a type path. @@ -6340,7 +6253,7 @@ Parser<ManagedTokenSource>::parse_type_path () } template <typename ManagedTokenSource> -AST::GenericArg +tl::optional<AST::GenericArg> Parser<ManagedTokenSource>::parse_generic_arg () { auto tok = lexer.peek_token (); @@ -6361,7 +6274,7 @@ Parser<ManagedTokenSource>::parse_generic_arg () if (type) return AST::GenericArg::create_type (std::move (type)); else - return AST::GenericArg::create_error (); + return tl::nullopt; } else if (next_tok->get_id () == COLON) { @@ -6378,7 +6291,7 @@ Parser<ManagedTokenSource>::parse_generic_arg () if (type) return AST::GenericArg::create_type (std::move (type)); else - return AST::GenericArg::create_error (); + return tl::nullopt; } lexer.skip_token (); return AST::GenericArg::create_ambiguous (tok->get_str (), @@ -6404,12 +6317,12 @@ Parser<ManagedTokenSource>::parse_generic_arg () if (type) return AST::GenericArg::create_type (std::move (type)); else - return AST::GenericArg::create_error (); + return tl::nullopt; } } if (!expr) - return AST::GenericArg::create_error (); + return tl::nullopt; return AST::GenericArg::create_const (std::move (expr)); } @@ -6438,14 +6351,14 @@ Parser<ManagedTokenSource>::parse_path_generic_args () location_t locus = t->get_locus (); while (!is_right_angle_tok (t->get_id ())) { - AST::Lifetime lifetime = parse_lifetime (false); - if (lifetime.is_error ()) + auto lifetime = parse_lifetime (false); + if (!lifetime) { // not necessarily an error break; } - lifetime_args.push_back (std::move (lifetime)); + lifetime_args.push_back (std::move (lifetime.value ())); // if next token isn't comma, then it must be end of list if (lexer.peek_token ()->get_id () != COMMA) @@ -6474,9 +6387,9 @@ Parser<ManagedTokenSource>::parse_path_generic_args () break; auto arg = parse_generic_arg (); - if (!arg.is_error ()) + if (arg) { - generic_args.emplace_back (std::move (arg)); + generic_args.emplace_back (std::move (arg.value ())); } // FIXME: Do we need to break if we encounter an error? @@ -7059,10 +6972,12 @@ Parser<ManagedTokenSource>::parse_self_param () // now test whether it has a lifetime if (lexer.peek_token ()->get_id () == LIFETIME) { - lifetime = parse_lifetime (true); - // something went wrong somehow - if (lifetime.is_error ()) + if (auto parsed_lifetime = parse_lifetime (true)) + { + lifetime = parsed_lifetime.value (); + } + else { Error error (lexer.peek_token ()->get_locus (), "failed to parse lifetime in self param"); @@ -7124,14 +7039,14 @@ Parser<ManagedTokenSource>::parse_self_param () if (has_reference) { - return Rust::make_unique<AST::SelfParam> (std::move (lifetime), has_mut, - locus); + return std::make_unique<AST::SelfParam> (std::move (lifetime), has_mut, + locus); } else { // note that type may be nullptr here and that's fine - return Rust::make_unique<AST::SelfParam> (std::move (type), has_mut, - locus); + return std::make_unique<AST::SelfParam> (std::move (type), has_mut, + locus); } } @@ -7251,9 +7166,9 @@ Parser<ManagedTokenSource>::parse_expr_stmt (AST::AttrVec outer_attrs, // Parses a block expression, including the curly braces at start and end. template <typename ManagedTokenSource> std::unique_ptr<AST::BlockExpr> -Parser<ManagedTokenSource>::parse_block_expr (AST::AttrVec outer_attrs, - AST::LoopLabel label, - location_t pratt_parsed_loc) +Parser<ManagedTokenSource>::parse_block_expr ( + AST::AttrVec outer_attrs, tl::optional<AST::LoopLabel> label, + location_t pratt_parsed_loc) { location_t locus = pratt_parsed_loc; if (locus == UNKNOWN_LOCATION) @@ -7617,12 +7532,10 @@ Parser<ManagedTokenSource>::parse_break_expr (AST::AttrVec outer_attrs, skip_token (BREAK); } - // parse label (lifetime) if it exists - create dummy first - AST::Lifetime label = AST::Lifetime::error (); - if (lexer.peek_token ()->get_id () == LIFETIME) - { - label = parse_lifetime (false); - } + auto parsed_label = parse_lifetime (false); + auto label = (parsed_label) + ? tl::optional<AST::Lifetime> (parsed_label.value ()) + : tl::nullopt; // parse break return expression if it exists ParseRestrictions restrictions; @@ -7648,12 +7561,10 @@ Parser<ManagedTokenSource>::parse_continue_expr (AST::AttrVec outer_attrs, skip_token (CONTINUE); } - // parse label (lifetime) if it exists - create dummy first - AST::Lifetime label = AST::Lifetime::error (); - if (lexer.peek_token ()->get_id () == LIFETIME) - { - label = parse_lifetime (false); - } + auto parsed_label = parse_lifetime (false); + auto label = (parsed_label) + ? tl::optional<AST::Lifetime> (parsed_label.value ()) + : tl::nullopt; return std::unique_ptr<AST::ContinueExpr> ( new AST::ContinueExpr (std::move (label), std::move (outer_attrs), locus)); @@ -7661,14 +7572,15 @@ Parser<ManagedTokenSource>::parse_continue_expr (AST::AttrVec outer_attrs, // Parses a loop label used in loop expressions. template <typename ManagedTokenSource> -AST::LoopLabel +tl::expected<AST::LoopLabel, ParseLoopLabelError> Parser<ManagedTokenSource>::parse_loop_label (const_TokenPtr tok) { // parse lifetime - if doesn't exist, assume no label if (tok->get_id () != LIFETIME) { // not necessarily an error - return AST::LoopLabel::error (); + return tl::unexpected<ParseLoopLabelError> ( + ParseLoopLabelError::NOT_LOOP_LABEL); } /* FIXME: check for named lifetime requirement here? or check in semantic * analysis phase? */ @@ -7677,10 +7589,12 @@ Parser<ManagedTokenSource>::parse_loop_label (const_TokenPtr tok) if (!skip_token (COLON)) { // skip somewhere? - return AST::LoopLabel::error (); + return tl::unexpected<ParseLoopLabelError> ( + ParseLoopLabelError::MISSING_COLON); } - return AST::LoopLabel (std::move (label), tok->get_locus ()); + return tl::expected<AST::LoopLabel, ParseLoopLabelError> ( + AST::LoopLabel (std::move (label), tok->get_locus ())); } /* Parses an if expression of any kind, including with else, else if, else if @@ -8033,16 +7947,16 @@ Parser<ManagedTokenSource>::parse_if_let_expr (AST::AttrVec outer_attrs, template <typename ManagedTokenSource> std::unique_ptr<AST::LoopExpr> Parser<ManagedTokenSource>::parse_loop_expr (AST::AttrVec outer_attrs, - AST::LoopLabel label, + tl::optional<AST::LoopLabel> label, location_t pratt_parsed_loc) { location_t locus = pratt_parsed_loc; if (locus == UNKNOWN_LOCATION) { - if (label.is_error ()) - locus = lexer.peek_token ()->get_locus (); + if (label) + locus = label->get_locus (); else - locus = label.get_locus (); + locus = lexer.peek_token ()->get_locus (); if (!skip_token (LOOP)) { @@ -8052,8 +7966,8 @@ Parser<ManagedTokenSource>::parse_loop_expr (AST::AttrVec outer_attrs, } else { - if (!label.is_error ()) - locus = label.get_locus (); + if (label) + locus = label->get_locus (); } // parse loop body, which is required @@ -8076,17 +7990,17 @@ Parser<ManagedTokenSource>::parse_loop_expr (AST::AttrVec outer_attrs, * via parse_labelled_loop_expr, which would call this. */ template <typename ManagedTokenSource> std::unique_ptr<AST::WhileLoopExpr> -Parser<ManagedTokenSource>::parse_while_loop_expr (AST::AttrVec outer_attrs, - AST::LoopLabel label, - location_t pratt_parsed_loc) +Parser<ManagedTokenSource>::parse_while_loop_expr ( + AST::AttrVec outer_attrs, tl::optional<AST::LoopLabel> label, + location_t pratt_parsed_loc) { location_t locus = pratt_parsed_loc; if (locus == UNKNOWN_LOCATION) { - if (label.is_error ()) - locus = lexer.peek_token ()->get_locus (); + if (label) + locus = label->get_locus (); else - locus = label.get_locus (); + locus = lexer.peek_token ()->get_locus (); if (!skip_token (WHILE)) { @@ -8096,8 +8010,8 @@ Parser<ManagedTokenSource>::parse_while_loop_expr (AST::AttrVec outer_attrs, } else { - if (!label.is_error ()) - locus = label.get_locus (); + if (label) + locus = label->get_locus (); } // ensure it isn't a while let loop @@ -8149,14 +8063,14 @@ Parser<ManagedTokenSource>::parse_while_loop_expr (AST::AttrVec outer_attrs, * parsed via parse_labelled_loop_expr, which would call this. */ template <typename ManagedTokenSource> std::unique_ptr<AST::WhileLetLoopExpr> -Parser<ManagedTokenSource>::parse_while_let_loop_expr (AST::AttrVec outer_attrs, - AST::LoopLabel label) +Parser<ManagedTokenSource>::parse_while_let_loop_expr ( + AST::AttrVec outer_attrs, tl::optional<AST::LoopLabel> label) { location_t locus = UNKNOWN_LOCATION; - if (label.is_error ()) - locus = lexer.peek_token ()->get_locus (); + if (label) + locus = label->get_locus (); else - locus = label.get_locus (); + locus = lexer.peek_token ()->get_locus (); maybe_skip_token (WHILE); /* check for possible accidental recognition of a while loop as a while let @@ -8223,14 +8137,14 @@ Parser<ManagedTokenSource>::parse_while_let_loop_expr (AST::AttrVec outer_attrs, * parse_labelled_loop_expr, which would call this. */ template <typename ManagedTokenSource> std::unique_ptr<AST::ForLoopExpr> -Parser<ManagedTokenSource>::parse_for_loop_expr (AST::AttrVec outer_attrs, - AST::LoopLabel label) +Parser<ManagedTokenSource>::parse_for_loop_expr ( + AST::AttrVec outer_attrs, tl::optional<AST::LoopLabel> label) { location_t locus = UNKNOWN_LOCATION; - if (label.is_error ()) - locus = lexer.peek_token ()->get_locus (); + if (label) + locus = label->get_locus (); else - locus = label.get_locus (); + locus = lexer.peek_token ()->get_locus (); maybe_skip_token (FOR); // parse pattern, which is required @@ -8308,8 +8222,9 @@ Parser<ManagedTokenSource>::parse_labelled_loop_expr (const_TokenPtr tok, } // parse loop label (required) - AST::LoopLabel label = parse_loop_label (tok); - if (label.is_error ()) + // TODO: Convert this return type to tl::expected instead of tl::optional + auto parsed_label = parse_loop_label (tok); + if (!parsed_label) { Error error (lexer.peek_token ()->get_locus (), "failed to parse loop label in labelled loop expr"); @@ -8319,6 +8234,10 @@ Parser<ManagedTokenSource>::parse_labelled_loop_expr (const_TokenPtr tok, return nullptr; } + auto label = parsed_label + ? tl::optional<AST::LoopLabel> (parsed_label.value ()) + : tl::nullopt; + // branch on next token const_TokenPtr t = lexer.peek_token (); switch (t->get_id ()) @@ -8693,10 +8612,10 @@ Parser<ManagedTokenSource>::parse_array_expr (AST::AttrVec outer_attrs, std::vector<std::unique_ptr<AST::Expr>> exprs; auto array_elems - = Rust::make_unique<AST::ArrayElemsValues> (std::move (exprs), locus); - return Rust::make_unique<AST::ArrayExpr> (std::move (array_elems), - std::move (inner_attrs), - std::move (outer_attrs), locus); + = std::make_unique<AST::ArrayElemsValues> (std::move (exprs), locus); + return std::make_unique<AST::ArrayExpr> (std::move (array_elems), + std::move (inner_attrs), + std::move (outer_attrs), locus); } else { @@ -9696,8 +9615,12 @@ Parser<ManagedTokenSource>::parse_reference_type_inner (location_t locus) AST::Lifetime lifetime = AST::Lifetime::elided (); if (lexer.peek_token ()->get_id () == LIFETIME) { - lifetime = parse_lifetime (true); - if (lifetime.is_error ()) + auto parsed_lifetime = parse_lifetime (true); + if (parsed_lifetime) + { + lifetime = parsed_lifetime.value (); + } + else { Error error (lexer.peek_token ()->get_locus (), "failed to parse lifetime in reference type"); @@ -12498,8 +12421,8 @@ Parser<ManagedTokenSource>::null_denotation_not_path ( return parse_continue_expr (std::move (outer_attrs), tok->get_locus ()); case LEFT_CURLY: // ok - this is an expression with block for once. - return parse_block_expr (std::move (outer_attrs), - AST::LoopLabel::error (), tok->get_locus ()); + return parse_block_expr (std::move (outer_attrs), tl::nullopt, + tok->get_locus ()); case IF: // if or if let, so more lookahead to find out if (lexer.peek_token ()->get_id () == LET) @@ -12515,7 +12438,7 @@ Parser<ManagedTokenSource>::null_denotation_not_path ( case LIFETIME: return parse_labelled_loop_expr (tok, std::move (outer_attrs)); case LOOP: - return parse_loop_expr (std::move (outer_attrs), AST::LoopLabel::error (), + return parse_loop_expr (std::move (outer_attrs), tl::nullopt, tok->get_locus ()); case WHILE: if (lexer.peek_token ()->get_id () == LET) @@ -12524,13 +12447,11 @@ Parser<ManagedTokenSource>::null_denotation_not_path ( } else { - return parse_while_loop_expr (std::move (outer_attrs), - AST::LoopLabel::error (), + return parse_while_loop_expr (std::move (outer_attrs), tl::nullopt, tok->get_locus ()); } case FOR: - return parse_for_loop_expr (std::move (outer_attrs), - AST::LoopLabel::error ()); + return parse_for_loop_expr (std::move (outer_attrs), tl::nullopt); case MATCH_KW: // also an expression with block return parse_match_expr (std::move (outer_attrs), tok->get_locus ()); diff --git a/gcc/rust/parse/rust-parse.h b/gcc/rust/parse/rust-parse.h index 95c0a0b..827d91d 100644 --- a/gcc/rust/parse/rust-parse.h +++ b/gcc/rust/parse/rust-parse.h @@ -25,6 +25,26 @@ along with GCC; see the file COPYING3. If not see #include "expected.h" namespace Rust { + +class ParseLifetimeParamError +{ +}; + +class ParseLifetimeError +{ +}; +enum class ParseLoopLabelError +{ + NOT_LOOP_LABEL, + MISSING_COLON, +}; +enum ParseSelfError +{ + SELF_PTR, + PARSING, + NOT_SELF, +}; + /* HACK: used to resolve the expression-or-statement problem at the end of a * block by allowing either to be returned (technically). Tagged union would * probably take up the same amount of space. */ @@ -95,12 +115,6 @@ struct ParseRestrictions bool allow_close_after_expr_stmt = false; }; -enum ParseSelfError -{ - SELF_PTR, - PARSING, - NOT_SELF, -}; // Parser implementation for gccrs. // TODO: if updated to C++20, ManagedTokenSource would be useful as a concept template <typename ManagedTokenSource> class Parser @@ -148,7 +162,7 @@ public: std::unique_ptr<AST::BlockExpr> parse_block_expr (AST::AttrVec outer_attrs = AST::AttrVec (), - AST::LoopLabel label = AST::LoopLabel::error (), + tl::optional<AST::LoopLabel> = tl::nullopt, location_t pratt_parsed_loc = UNKNOWN_LOCATION); bool is_macro_rules_def (const_TokenPtr t); @@ -212,7 +226,7 @@ private: AST::TypePath parse_type_path (); std::unique_ptr<AST::TypePathSegment> parse_type_path_segment (); AST::PathIdentSegment parse_path_ident_segment (); - AST::GenericArg parse_generic_arg (); + tl::optional<AST::GenericArg> parse_generic_arg (); AST::GenericArgs parse_path_generic_args (); AST::GenericArgsBinding parse_generic_args_binding (); AST::TypePathFunction parse_type_path_function (location_t locus); @@ -277,7 +291,8 @@ private: ParseFunction parsing_function, EndTokenPred is_end_token, std::string error_msg = "failed to parse generic param in generic params") -> std::vector<decltype (parsing_function ())>; - AST::LifetimeParam parse_lifetime_param (); + tl::expected<AST::LifetimeParam, ParseLifetimeParamError> + parse_lifetime_param (); std::vector<std::unique_ptr<AST::TypeParam>> parse_type_params (); template <typename EndTokenPred> std::vector<std::unique_ptr<AST::TypeParam>> @@ -306,14 +321,11 @@ private: std::vector<AST::Lifetime> parse_lifetime_bounds (); template <typename EndTokenPred> std::vector<AST::Lifetime> parse_lifetime_bounds (EndTokenPred is_end_token); - AST::Lifetime parse_lifetime (bool allow_elided); + tl::expected<AST::Lifetime, ParseLifetimeError> + parse_lifetime (bool allow_elided); AST::Lifetime lifetime_from_token (const_TokenPtr tok); std::unique_ptr<AST::ExternalTypeItem> parse_external_type_item (AST::Visibility vis, AST::AttrVec outer_attrs); - AST::NamedFunctionParam parse_named_function_param (); - template <typename EndTokenPred> - std::vector<AST::NamedFunctionParam> - parse_named_function_params (EndTokenPred is_end_token); std::unique_ptr<AST::TypeAlias> parse_type_alias (AST::Visibility vis, AST::AttrVec outer_attrs); @@ -592,18 +604,18 @@ private: location_t pratt_parsed_loc = UNKNOWN_LOCATION); std::unique_ptr<AST::LoopExpr> parse_loop_expr (AST::AttrVec outer_attrs = AST::AttrVec (), - AST::LoopLabel label = AST::LoopLabel::error (), + tl::optional<AST::LoopLabel> label = tl::nullopt, location_t pratt_parsed_loc = UNKNOWN_LOCATION); std::unique_ptr<AST::WhileLoopExpr> parse_while_loop_expr (AST::AttrVec outer_attrs = AST::AttrVec (), - AST::LoopLabel label = AST::LoopLabel::error (), + tl::optional<AST::LoopLabel> label = tl::nullopt, location_t pratt_parsed_loc = UNKNOWN_LOCATION); std::unique_ptr<AST::WhileLetLoopExpr> parse_while_let_loop_expr (AST::AttrVec outer_attrs = AST::AttrVec (), - AST::LoopLabel label = AST::LoopLabel::error ()); + tl::optional<AST::LoopLabel> label = tl::nullopt); std::unique_ptr<AST::ForLoopExpr> parse_for_loop_expr (AST::AttrVec outer_attrs = AST::AttrVec (), - AST::LoopLabel label = AST::LoopLabel::error ()); + tl::optional<AST::LoopLabel> label = tl::nullopt); std::unique_ptr<AST::MatchExpr> parse_match_expr (AST::AttrVec outer_attrs = AST::AttrVec (), location_t pratt_parsed_loc = UNKNOWN_LOCATION); @@ -613,7 +625,8 @@ private: std::unique_ptr<AST::Expr> parse_labelled_loop_expr (const_TokenPtr tok, AST::AttrVec outer_attrs = AST::AttrVec ()); - AST::LoopLabel parse_loop_label (const_TokenPtr tok); + tl::expected<AST::LoopLabel, ParseLoopLabelError> + parse_loop_label (const_TokenPtr tok); std::unique_ptr<AST::AsyncBlockExpr> parse_async_block_expr (AST::AttrVec outer_attrs = AST::AttrVec ()); std::unique_ptr<AST::GroupedExpr> parse_grouped_expr (AST::AttrVec outer_attrs diff --git a/gcc/rust/resolve/rust-ast-resolve-base.cc b/gcc/rust/resolve/rust-ast-resolve-base.cc index 69f146c..b781ce33 100644 --- a/gcc/rust/resolve/rust-ast-resolve-base.cc +++ b/gcc/rust/resolve/rust-ast-resolve-base.cc @@ -20,6 +20,7 @@ #include "rust-ast-resolve-expr.h" #include "rust-ast-resolve-path.h" #include "rust-item.h" +#include "rust-path.h" namespace Rust { namespace Resolver { @@ -327,6 +328,10 @@ ResolverBase::visit (AST::InlineAsm &) {} void +ResolverBase::visit (AST::LlvmInlineAsm &) +{} + +void ResolverBase::visit (AST::TypeParam &) {} diff --git a/gcc/rust/resolve/rust-ast-resolve-base.h b/gcc/rust/resolve/rust-ast-resolve-base.h index 0d497f8..5bb9e4f 100644 --- a/gcc/rust/resolve/rust-ast-resolve-base.h +++ b/gcc/rust/resolve/rust-ast-resolve-base.h @@ -27,6 +27,11 @@ namespace Rust { namespace Resolver { +inline void +redefined_error (const rich_location &loc) +{ + rust_error_at (loc, "redefined multiple times"); +} class ResolverBase : public AST::ASTVisitor { @@ -105,6 +110,7 @@ public: void visit (AST::AwaitExpr &); void visit (AST::AsyncBlockExpr &); void visit (AST::InlineAsm &); + void visit (AST::LlvmInlineAsm &); void visit (AST::TypeParam &); diff --git a/gcc/rust/resolve/rust-ast-resolve-expr.cc b/gcc/rust/resolve/rust-ast-resolve-expr.cc index 44ba2a8..6242235 100644 --- a/gcc/rust/resolve/rust-ast-resolve-expr.cc +++ b/gcc/rust/resolve/rust-ast-resolve-expr.cc @@ -22,7 +22,8 @@ #include "rust-ast-resolve-type.h" #include "rust-ast-resolve-pattern.h" #include "rust-ast-resolve-path.h" -#include "diagnostic.h" +#include "rust-expr.h" +#include "rust-ice-finalizer.h" namespace Rust { namespace Resolver { @@ -95,50 +96,16 @@ ResolveExpr::visit (AST::MethodCallExpr &expr) } void -ResolveExpr::visit (AST::AssignmentExpr &expr) +ResolveExpr::visit (AST::ErrorPropagationExpr &expr) { - ResolveExpr::go (expr.get_left_expr (), prefix, canonical_prefix); - ResolveExpr::go (expr.get_right_expr (), prefix, canonical_prefix); + ResolveExpr::go (expr.get_propagating_expr (), prefix, canonical_prefix); } -/* The "break rust" Easter egg. - - Backstory: once upon a time, there used to be a bug in rustc: it would ICE - during typechecking on a 'break' with an expression outside of a loop. The - issue has been reported [0] and fixed [1], but in recognition of this, as a - special Easter egg, "break rust" was made to intentionally cause an ICE. - - [0]: https://github.com/rust-lang/rust/issues/43162 - [1]: https://github.com/rust-lang/rust/pull/43745 - - This was made in a way that does not break valid programs: namely, it only - happens when the 'break' is outside of a loop (so invalid anyway). - - GCC Rust supports this essential feature as well, but in a slightly - different way. Instead of delaying the error until type checking, we emit - it here in the resolution phase. We, too, only do this to programs that - are already invalid: we only emit our funny ICE if the name "rust" (which - must be immediately inside a break-with-a-value expression) fails to - resolve. Note that "break (rust)" does not trigger our ICE, only using - "break rust" directly does, and only if there's no "rust" in scope. We do - this in the same way regardless of whether the "break" is outside of a loop - or inside one. - - As a GNU extension, we also support "break gcc", much to the same effect, - subject to the same rules. */ - -/* The finalizer for our funny ICE. This prints a custom message instead of - the default bug reporting instructions, as there is no bug to report. */ - -static void ATTRIBUTE_NORETURN -funny_ice_text_finalizer (diagnostic_text_output_format &text_output, - const diagnostic_info *diagnostic, - diagnostic_t diag_kind) +void +ResolveExpr::visit (AST::AssignmentExpr &expr) { - gcc_assert (diag_kind == DK_ICE_NOBT); - default_diagnostic_text_finalizer (text_output, diagnostic, diag_kind); - fnotice (stderr, "You have broken GCC Rust. This is a feature.\n"); - exit (ICE_EXIT_CODE); + ResolveExpr::go (expr.get_left_expr (), prefix, canonical_prefix); + ResolveExpr::go (expr.get_right_expr (), prefix, canonical_prefix); } void @@ -242,7 +209,7 @@ ResolveExpr::visit (AST::IfLetExpr &expr) resolver->get_label_scope ().push (scope_node_id); resolver->push_new_name_rib (resolver->get_name_scope ().peek ()); resolver->push_new_type_rib (resolver->get_type_scope ().peek ()); - resolver->push_new_label_rib (resolver->get_type_scope ().peek ()); + resolver->push_new_label_rib (resolver->get_label_scope ().peek ()); // We know expr.get_patterns () has one pattern at most // so there's no reason to handle it like an AltPattern. @@ -272,7 +239,7 @@ ResolveExpr::visit (AST::IfLetExprConseqElse &expr) resolver->get_label_scope ().push (scope_node_id); resolver->push_new_name_rib (resolver->get_name_scope ().peek ()); resolver->push_new_type_rib (resolver->get_type_scope ().peek ()); - resolver->push_new_label_rib (resolver->get_type_scope ().peek ()); + resolver->push_new_label_rib (resolver->get_label_scope ().peek ()); // We know expr.get_patterns () has one pattern at most // so there's no reason to handle it like an AltPattern. @@ -301,7 +268,7 @@ ResolveExpr::visit (AST::BlockExpr &expr) resolver->get_label_scope ().push (scope_node_id); resolver->push_new_name_rib (resolver->get_name_scope ().peek ()); resolver->push_new_type_rib (resolver->get_type_scope ().peek ()); - resolver->push_new_label_rib (resolver->get_type_scope ().peek ()); + resolver->push_new_label_rib (resolver->get_label_scope ().peek ()); if (expr.has_label ()) { @@ -320,7 +287,7 @@ ResolveExpr::visit (AST::BlockExpr &expr) CanonicalPath::new_seg (label.get_node_id (), label_name), label_lifetime_node_id, label.get_locus (), false, Rib::ItemType::Label, [&] (const CanonicalPath &, NodeId, location_t locus) -> void { - rust_error_at (label.get_locus (), "label redefined multiple times"); + rust_error_at (label.get_locus (), "label defined multiple times"); rust_error_at (locus, "was defined here"); }); } @@ -348,6 +315,71 @@ ResolveExpr::visit (AST::BlockExpr &expr) } void +translate_operand (AST::InlineAsm &expr, const CanonicalPath &prefix, + const CanonicalPath &canonical_prefix) +{ + const auto &operands = expr.get_operands (); + using RegisterType = AST::InlineAsmOperand::RegisterType; + for (auto &operand : operands) + { + switch (operand.get_register_type ()) + { + case RegisterType::In: { + auto in = operand.get_in (); + ResolveExpr::go (*in.expr, prefix, canonical_prefix); + break; + } + case RegisterType::Out: { + auto out = operand.get_out (); + ResolveExpr::go (*out.expr, prefix, canonical_prefix); + break; + } + case RegisterType::InOut: { + auto in_out = operand.get_in_out (); + ResolveExpr::go (*in_out.expr, prefix, canonical_prefix); + break; + } + case RegisterType::SplitInOut: { + auto split_in_out = operand.get_split_in_out (); + ResolveExpr::go (*split_in_out.in_expr, prefix, canonical_prefix); + ResolveExpr::go (*split_in_out.out_expr, prefix, canonical_prefix); + break; + } + case RegisterType::Const: { + auto anon_const = operand.get_const ().anon_const; + ResolveExpr::go (*anon_const.expr, prefix, canonical_prefix); + break; + } + case RegisterType::Sym: { + auto sym = operand.get_sym (); + ResolveExpr::go (*sym.expr, prefix, canonical_prefix); + break; + } + case RegisterType::Label: { + auto label = operand.get_label (); + ResolveExpr::go (*label.expr, prefix, canonical_prefix); + break; + } + } + } +} +void +ResolveExpr::visit (AST::InlineAsm &expr) +{ + translate_operand (expr, prefix, canonical_prefix); +} + +void +ResolveExpr::visit (AST::LlvmInlineAsm &expr) +{ + for (auto &output : expr.get_outputs ()) + ResolveExpr::go (*output.expr, prefix, canonical_prefix); + + for (auto &input : expr.get_inputs ()) + ResolveExpr::go (*input.expr, prefix, canonical_prefix); +} + +void ResolveExpr::visit (AST::UnsafeBlockExpr &expr) { expr.get_block_expr ().accept_vis (*this); @@ -438,7 +470,7 @@ ResolveExpr::visit (AST::LoopExpr &expr) CanonicalPath::new_seg (expr.get_node_id (), label_name), label_lifetime_node_id, label.get_locus (), false, Rib::ItemType::Label, [&] (const CanonicalPath &, NodeId, location_t locus) -> void { - rust_error_at (label.get_locus (), "label redefined multiple times"); + rust_error_at (label.get_locus (), "label defined multiple times"); rust_error_at (locus, "was defined here"); }); } @@ -450,7 +482,7 @@ ResolveExpr::visit (AST::BreakExpr &expr) { if (expr.has_label ()) { - auto label = expr.get_label ().get_lifetime (); + auto label = expr.get_label_unchecked ().get_lifetime (); if (label.get_lifetime_type () != AST::Lifetime::LifetimeType::NAMED) { rust_error_at (label.get_locus (), @@ -465,8 +497,8 @@ ResolveExpr::visit (AST::BreakExpr &expr) &resolved_node)) { rust_error_at (label.get_locus (), ErrorCode::E0426, - "use of undeclared label %qs in %<break%>", - label.get_lifetime_name ().c_str ()); + "use of undeclared label %qs", + label.as_string ().c_str ()); return; } resolver->insert_resolved_label (label.get_node_id (), resolved_node); @@ -476,14 +508,15 @@ ResolveExpr::visit (AST::BreakExpr &expr) { bool funny_error = false; auto &break_expr = expr.get_break_expr (); - if (break_expr.get_ast_kind () == AST::Kind::IDENTIFIER) + if (break_expr.get_expr_kind () == AST::Expr::Kind::Identifier) { - /* This is a break with an expression, and the expression is just a - single identifier. See if the identifier is either "rust" or - "gcc", in which case we have "break rust" or "break gcc", and so - may need to emit our funny error. We cannot yet emit the error - here though, because the identifier may still be in scope, and - ICE'ing on valid programs would not be very funny. */ + /* This is a break with an expression, and the expression is + just a single identifier. See if the identifier is either + "rust" or "gcc", in which case we have "break rust" or "break + gcc", and so may need to emit our funny error. We cannot yet + emit the error here though, because the identifier may still + be in scope, and ICE'ing on valid programs would not be very + funny. */ std::string ident = static_cast<AST::IdentifierExpr &> (break_expr).as_string (); if (ident == "rust" || ident == "gcc") @@ -513,7 +546,7 @@ ResolveExpr::visit (AST::WhileLoopExpr &expr) CanonicalPath::new_seg (label.get_node_id (), label_name), label_lifetime_node_id, label.get_locus (), false, Rib::ItemType::Label, [&] (const CanonicalPath &, NodeId, location_t locus) -> void { - rust_error_at (label.get_locus (), "label redefined multiple times"); + rust_error_at (label.get_locus (), "label defined multiple times"); rust_error_at (locus, "was defined here"); }); } @@ -542,7 +575,7 @@ ResolveExpr::visit (AST::ForLoopExpr &expr) CanonicalPath::new_seg (label.get_node_id (), label_name), label_lifetime_node_id, label.get_locus (), false, Rib::ItemType::Label, [&] (const CanonicalPath &, NodeId, location_t locus) -> void { - rust_error_at (label.get_locus (), "label redefined multiple times"); + rust_error_at (label.get_locus (), "label defined multiple times"); rust_error_at (locus, "was defined here"); }); } @@ -554,7 +587,7 @@ ResolveExpr::visit (AST::ForLoopExpr &expr) resolver->get_label_scope ().push (scope_node_id); resolver->push_new_name_rib (resolver->get_name_scope ().peek ()); resolver->push_new_type_rib (resolver->get_type_scope ().peek ()); - resolver->push_new_label_rib (resolver->get_type_scope ().peek ()); + resolver->push_new_label_rib (resolver->get_label_scope ().peek ()); // resolve the expression PatternDeclaration::go (expr.get_pattern (), Rib::ItemType::Var); @@ -572,7 +605,7 @@ ResolveExpr::visit (AST::ContinueExpr &expr) { if (expr.has_label ()) { - auto label = expr.get_label (); + auto label = expr.get_label_unchecked (); if (label.get_lifetime_type () != AST::Lifetime::LifetimeType::NAMED) { rust_error_at (label.get_locus (), @@ -586,9 +619,9 @@ ResolveExpr::visit (AST::ContinueExpr &expr) label.get_lifetime_name ()), &resolved_node)) { - rust_error_at (expr.get_label ().get_locus (), ErrorCode::E0426, - "use of undeclared label %qs in %<continue%>", - label.get_lifetime_name ().c_str ()); + rust_error_at (expr.get_label_unchecked ().get_locus (), + ErrorCode::E0426, "use of undeclared label %qs", + label.as_string ().c_str ()); return; } resolver->insert_resolved_label (label.get_node_id (), resolved_node); @@ -620,7 +653,7 @@ ResolveExpr::visit (AST::MatchExpr &expr) resolver->get_label_scope ().push (scope_node_id); resolver->push_new_name_rib (resolver->get_name_scope ().peek ()); resolver->push_new_type_rib (resolver->get_type_scope ().peek ()); - resolver->push_new_label_rib (resolver->get_type_scope ().peek ()); + resolver->push_new_label_rib (resolver->get_label_scope ().peek ()); // resolve AST::MatchArm &arm = match_case.get_arm (); @@ -689,7 +722,7 @@ ResolveExpr::visit (AST::ClosureExprInner &expr) resolver->get_label_scope ().push (scope_node_id); resolver->push_new_name_rib (resolver->get_name_scope ().peek ()); resolver->push_new_type_rib (resolver->get_type_scope ().peek ()); - resolver->push_new_label_rib (resolver->get_type_scope ().peek ()); + resolver->push_new_label_rib (resolver->get_label_scope ().peek ()); std::vector<PatternBinding> bindings = {PatternBinding (PatternBoundCtx::Product, std::set<Identifier> ())}; @@ -719,7 +752,7 @@ ResolveExpr::visit (AST::ClosureExprInnerTyped &expr) resolver->get_label_scope ().push (scope_node_id); resolver->push_new_name_rib (resolver->get_name_scope ().peek ()); resolver->push_new_type_rib (resolver->get_type_scope ().peek ()); - resolver->push_new_label_rib (resolver->get_type_scope ().peek ()); + resolver->push_new_label_rib (resolver->get_label_scope ().peek ()); std::vector<PatternBinding> bindings = {PatternBinding (PatternBoundCtx::Product, std::set<Identifier> ())}; diff --git a/gcc/rust/resolve/rust-ast-resolve-expr.h b/gcc/rust/resolve/rust-ast-resolve-expr.h index 75b07b8..b296d66 100644 --- a/gcc/rust/resolve/rust-ast-resolve-expr.h +++ b/gcc/rust/resolve/rust-ast-resolve-expr.h @@ -20,7 +20,9 @@ #define RUST_AST_RESOLVE_EXPR_H #include "rust-ast-resolve-base.h" +#include "rust-ast.h" #include "rust-ast-resolve-pattern.h" +#include "rust-expr.h" namespace Rust { namespace Resolver { @@ -54,6 +56,8 @@ public: void visit (AST::IfLetExpr &expr) override; void visit (AST::IfLetExprConseqElse &expr) override; void visit (AST::BlockExpr &expr) override; + void visit (AST::InlineAsm &expr) override; + void visit (AST::LlvmInlineAsm &expr) override; void visit (AST::UnsafeBlockExpr &expr) override; void visit (AST::ArrayElemsValues &elems) override; void visit (AST::ArrayExpr &expr) override; @@ -78,6 +82,7 @@ public: void visit (AST::RangeFromToInclExpr &expr) override; void visit (AST::ClosureExprInner &expr) override; void visit (AST::ClosureExprInnerTyped &expr) override; + void visit (AST::ErrorPropagationExpr &expr) override; protected: void resolve_closure_param (AST::ClosureParam ¶m, diff --git a/gcc/rust/resolve/rust-ast-resolve-implitem.h b/gcc/rust/resolve/rust-ast-resolve-implitem.h index 2ca1296..2081697 100644 --- a/gcc/rust/resolve/rust-ast-resolve-implitem.h +++ b/gcc/rust/resolve/rust-ast-resolve-implitem.h @@ -51,7 +51,7 @@ public: [&] (const CanonicalPath &, NodeId, location_t locus) -> void { rich_location r (line_table, type.get_locus ()); r.add_range (locus); - rust_error_at (r, "redefined multiple times"); + redefined_error (r); }); } @@ -67,7 +67,7 @@ public: [&] (const CanonicalPath &, NodeId, location_t locus) -> void { rich_location r (line_table, constant.get_locus ()); r.add_range (locus); - rust_error_at (r, "redefined multiple times"); + redefined_error (r); }); } @@ -84,7 +84,7 @@ public: [&] (const CanonicalPath &, NodeId, location_t locus) -> void { rich_location r (line_table, function.get_locus ()); r.add_range (locus); - rust_error_at (r, "redefined multiple times"); + redefined_error (r); }); } @@ -124,7 +124,7 @@ public: [&] (const CanonicalPath &, NodeId, location_t locus) -> void { rich_location r (line_table, function.get_locus ()); r.add_range (locus); - rust_error_at (r, "redefined multiple times"); + redefined_error (r); }); mappings.insert_canonical_path (function.get_node_id (), cpath); @@ -144,7 +144,7 @@ public: [&] (const CanonicalPath &, NodeId, location_t locus) -> void { rich_location r (line_table, constant.get_locus ()); r.add_range (locus); - rust_error_at (r, "redefined multiple times"); + redefined_error (r); }); mappings.insert_canonical_path (constant.get_node_id (), cpath); @@ -162,7 +162,7 @@ public: [&] (const CanonicalPath &, NodeId, location_t locus) -> void { rich_location r (line_table, type.get_locus ()); r.add_range (locus); - rust_error_at (r, "redefined multiple times"); + redefined_error (r); }); mappings.insert_canonical_path (type.get_node_id (), cpath); @@ -202,7 +202,7 @@ public: [&] (const CanonicalPath &, NodeId, location_t locus) -> void { rich_location r (line_table, function.get_locus ()); r.add_range (locus); - rust_error_at (r, "redefined multiple times"); + redefined_error (r); }); NodeId current_module = resolver->peek_current_module_scope (); @@ -221,7 +221,7 @@ public: [&] (const CanonicalPath &, NodeId, location_t locus) -> void { rich_location r (line_table, item.get_locus ()); r.add_range (locus); - rust_error_at (r, "redefined multiple times"); + redefined_error (r); }); NodeId current_module = resolver->peek_current_module_scope (); @@ -239,8 +239,7 @@ public: [&] (const CanonicalPath &, NodeId, location_t locus) -> void { rich_location r (line_table, type.get_locus ()); r.add_range (locus); - - rust_error_at (r, "redefined multiple times"); + redefined_error (r); }); NodeId current_module = resolver->peek_current_module_scope (); diff --git a/gcc/rust/resolve/rust-ast-resolve-item.cc b/gcc/rust/resolve/rust-ast-resolve-item.cc index 34098bc..30f6d43 100644 --- a/gcc/rust/resolve/rust-ast-resolve-item.cc +++ b/gcc/rust/resolve/rust-ast-resolve-item.cc @@ -61,11 +61,11 @@ ResolveTraitItems::visit (AST::Function &function) resolver->get_label_scope ().push (scope_node_id); resolver->push_new_name_rib (resolver->get_name_scope ().peek ()); resolver->push_new_type_rib (resolver->get_type_scope ().peek ()); - resolver->push_new_label_rib (resolver->get_type_scope ().peek ()); + resolver->push_new_label_rib (resolver->get_label_scope ().peek ()); if (function.has_generics ()) - for (auto &generic : function.get_generic_params ()) - ResolveGenericParam::go (*generic, prefix, canonical_prefix); + ResolveGenericParams::go (function.get_generic_params (), prefix, + canonical_prefix); if (function.has_return_type ()) ResolveType::go (function.get_return_type ()); @@ -188,8 +188,8 @@ ResolveItem::visit (AST::TypeAlias &alias) resolver->get_type_scope ().push (scope_node_id); if (alias.has_generics ()) - for (auto &generic : alias.get_generic_params ()) - ResolveGenericParam::go (*generic, prefix, canonical_prefix); + ResolveGenericParams::go (alias.get_generic_params (), prefix, + canonical_prefix); if (alias.has_where_clause ()) ResolveWhereClause::Resolve (alias.get_where_clause ()); @@ -216,7 +216,7 @@ ResolveItem::visit (AST::Module &module) resolver->get_label_scope ().push (scope_node_id); resolver->push_new_name_rib (resolver->get_name_scope ().peek ()); resolver->push_new_type_rib (resolver->get_type_scope ().peek ()); - resolver->push_new_label_rib (resolver->get_type_scope ().peek ()); + resolver->push_new_label_rib (resolver->get_label_scope ().peek ()); // FIXME: Should we reinsert a child here? Any reason we ResolveTopLevel::go // in ResolveTopLevel::visit (AST::Module) as well as here? @@ -250,8 +250,8 @@ ResolveItem::visit (AST::TupleStruct &struct_decl) resolver->get_type_scope ().push (scope_node_id); if (struct_decl.has_generics ()) - for (auto &generic : struct_decl.get_generic_params ()) - ResolveGenericParam::go (*generic, prefix, canonical_prefix); + ResolveGenericParams::go (struct_decl.get_generic_params (), prefix, + canonical_prefix); if (struct_decl.has_where_clause ()) ResolveWhereClause::Resolve (struct_decl.get_where_clause ()); @@ -284,8 +284,8 @@ ResolveItem::visit (AST::Enum &enum_decl) resolver->get_type_scope ().push (scope_node_id); if (enum_decl.has_generics ()) - for (auto &generic : enum_decl.get_generic_params ()) - ResolveGenericParam::go (*generic, prefix, cpath); + ResolveGenericParams::go (enum_decl.get_generic_params (), prefix, + canonical_prefix); if (enum_decl.has_where_clause ()) ResolveWhereClause::Resolve (enum_decl.get_where_clause ()); @@ -356,6 +356,8 @@ ResolveItem::visit (AST::EnumItemDiscriminant &item) auto cpath = canonical_prefix.append (decl); mappings.insert_canonical_path (item.get_node_id (), cpath); + + ResolveExpr::go (item.get_expr (), path, cpath); } void @@ -374,8 +376,8 @@ ResolveItem::visit (AST::StructStruct &struct_decl) resolver->get_type_scope ().push (scope_node_id); if (struct_decl.has_generics ()) - for (auto &generic : struct_decl.get_generic_params ()) - ResolveGenericParam::go (*generic, prefix, canonical_prefix); + ResolveGenericParams::go (struct_decl.get_generic_params (), prefix, + canonical_prefix); if (struct_decl.has_where_clause ()) ResolveWhereClause::Resolve (struct_decl.get_where_clause ()); @@ -409,8 +411,8 @@ ResolveItem::visit (AST::Union &union_decl) resolver->get_type_scope ().push (scope_node_id); if (union_decl.has_generics ()) - for (auto &generic : union_decl.get_generic_params ()) - ResolveGenericParam::go (*generic, prefix, canonical_prefix); + ResolveGenericParams::go (union_decl.get_generic_params (), prefix, + canonical_prefix); if (union_decl.has_where_clause ()) ResolveWhereClause::Resolve (union_decl.get_where_clause ()); @@ -473,11 +475,11 @@ ResolveItem::visit (AST::Function &function) resolver->get_label_scope ().push (scope_node_id); resolver->push_new_name_rib (resolver->get_name_scope ().peek ()); resolver->push_new_type_rib (resolver->get_type_scope ().peek ()); - resolver->push_new_label_rib (resolver->get_type_scope ().peek ()); + resolver->push_new_label_rib (resolver->get_label_scope ().peek ()); if (function.has_generics ()) - for (auto &generic : function.get_generic_params ()) - ResolveGenericParam::go (*generic, prefix, canonical_prefix); + ResolveGenericParams::go (function.get_generic_params (), prefix, + canonical_prefix); // resolve any where clause items if (function.has_where_clause ()) @@ -567,8 +569,8 @@ ResolveItem::visit (AST::InherentImpl &impl_block) resolve_visibility (impl_block.get_visibility ()); if (impl_block.has_generics ()) - for (auto &generic : impl_block.get_generic_params ()) - ResolveGenericParam::go (*generic, prefix, canonical_prefix); + ResolveGenericParams::go (impl_block.get_generic_params (), prefix, + canonical_prefix); // resolve any where clause items if (impl_block.has_where_clause ()) @@ -582,7 +584,14 @@ ResolveItem::visit (AST::InherentImpl &impl_block) // Setup paths CanonicalPath self_cpath = CanonicalPath::create_empty (); bool ok = ResolveTypeToCanonicalPath::go (impl_block.get_type (), self_cpath); - rust_assert (ok); + if (!ok) + { + resolver->get_name_scope ().pop (); + resolver->get_type_scope ().pop (); + resolver->get_label_scope ().pop (); + return; + } + rust_debug ("AST::InherentImpl resolve Self: {%s}", self_cpath.get ().c_str ()); @@ -641,11 +650,11 @@ ResolveItem::visit (AST::TraitImpl &impl_block) resolver->get_label_scope ().push (scope_node_id); resolver->push_new_name_rib (resolver->get_name_scope ().peek ()); resolver->push_new_type_rib (resolver->get_type_scope ().peek ()); - resolver->push_new_label_rib (resolver->get_type_scope ().peek ()); + resolver->push_new_label_rib (resolver->get_label_scope ().peek ()); if (impl_block.has_generics ()) - for (auto &generic : impl_block.get_generic_params ()) - ResolveGenericParam::go (*generic, prefix, canonical_prefix); + ResolveGenericParams::go (impl_block.get_generic_params (), prefix, + canonical_prefix); // resolve any where clause items if (impl_block.has_where_clause ()) @@ -671,12 +680,20 @@ ResolveItem::visit (AST::TraitImpl &impl_block) return; } - bool ok; + bool ok = true; + // setup paths CanonicalPath canonical_trait_type = CanonicalPath::create_empty (); + ok = ResolveTypeToCanonicalPath::go (impl_block.get_trait_path (), canonical_trait_type); - rust_assert (ok); + if (!ok) + { + resolver->get_name_scope ().pop (); + resolver->get_type_scope ().pop (); + resolver->get_label_scope ().pop (); + return; + } rust_debug ("AST::TraitImpl resolve trait type: {%s}", canonical_trait_type.get ().c_str ()); @@ -684,7 +701,13 @@ ResolveItem::visit (AST::TraitImpl &impl_block) CanonicalPath canonical_impl_type = CanonicalPath::create_empty (); ok = ResolveTypeToCanonicalPath::go (impl_block.get_type (), canonical_impl_type); - rust_assert (ok); + if (!ok) + { + resolver->get_name_scope ().pop (); + resolver->get_type_scope ().pop (); + resolver->get_label_scope ().pop (); + return; + } rust_debug ("AST::TraitImpl resolve self: {%s}", canonical_impl_type.get ().c_str ()); @@ -755,20 +778,14 @@ ResolveItem::visit (AST::Trait &trait) resolver->push_new_name_rib (resolver->get_name_scope ().peek ()); resolver->push_new_type_rib (resolver->get_type_scope ().peek ()); - // we need to inject an implicit self TypeParam here - // FIXME: which location should be used for Rust::Identifier `Self`? - AST::TypeParam *implicit_self - = new AST::TypeParam ({"Self"}, trait.get_locus ()); - trait.insert_implict_self ( - std::unique_ptr<AST::GenericParam> (implicit_self)); - CanonicalPath Self = CanonicalPath::get_big_self (trait.get_node_id ()); - - for (auto &generic : trait.get_generic_params ()) - ResolveGenericParam::go (*generic, prefix, canonical_prefix); + ResolveGenericParams::go_single (trait.get_implicit_self (), prefix, + canonical_prefix); + ResolveGenericParams::go (trait.get_generic_params (), prefix, + canonical_prefix); // Self is an implicit TypeParam so lets mark it as such resolver->get_type_scope ().append_reference_for_def ( - Self.get_node_id (), implicit_self->get_node_id ()); + trait.get_node_id (), trait.get_implicit_self ().get_node_id ()); if (trait.has_type_param_bounds ()) { @@ -888,7 +905,18 @@ flatten_list (const AST::UseTreeList &list, std::vector<Import> &imports) for (auto import = imports.begin () + start_idx; import != imports.end (); import++) - import->add_prefix (prefix); + { + // avoid duplicate node ids + auto prefix_copy + = AST::SimplePath ({}, prefix.has_opening_scope_resolution (), + prefix.get_locus ()); + for (auto &seg : prefix.get_segments ()) + prefix_copy.get_segments ().push_back ( + AST::SimplePathSegment (seg.get_segment_name (), + seg.get_locus ())); + + import->add_prefix (std::move (prefix_copy)); + } } } @@ -1025,12 +1053,12 @@ ResolveExternItem::visit (AST::Function &function) resolver->get_label_scope ().push (scope_node_id); resolver->push_new_name_rib (resolver->get_name_scope ().peek ()); resolver->push_new_type_rib (resolver->get_type_scope ().peek ()); - resolver->push_new_label_rib (resolver->get_type_scope ().peek ()); + resolver->push_new_label_rib (resolver->get_label_scope ().peek ()); // resolve the generics if (function.has_generics ()) - for (auto &generic : function.get_generic_params ()) - ResolveGenericParam::go (*generic, prefix, canonical_prefix); + ResolveGenericParams::go (function.get_generic_params (), prefix, + canonical_prefix); if (function.has_return_type ()) ResolveType::go (function.get_return_type ()); diff --git a/gcc/rust/resolve/rust-ast-resolve-path.cc b/gcc/rust/resolve/rust-ast-resolve-path.cc index ea39fd4..fb6715d 100644 --- a/gcc/rust/resolve/rust-ast-resolve-path.cc +++ b/gcc/rust/resolve/rust-ast-resolve-path.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2025 Free Software Foundation, Inc. +// Copyright (C) 2020-2024 Free Software Foundation, Inc. // This file is part of GCC. @@ -18,6 +18,7 @@ #include "rust-ast-resolve-path.h" #include "rust-ast-resolve-type.h" +#include "rust-hir-map.h" #include "rust-path.h" namespace Rust { @@ -49,6 +50,10 @@ ResolvePath::go (AST::SimplePath &expr) NodeId ResolvePath::resolve_path (AST::PathInExpression &expr) { + if (expr.is_lang_item ()) + return Analysis::Mappings::get ().get_lang_item_node ( + expr.get_lang_item ()); + NodeId resolved_node_id = UNKNOWN_NODEID; NodeId module_scope_id = resolver->peek_current_module_scope (); NodeId previous_resolved_node_id = module_scope_id; @@ -63,8 +68,7 @@ ResolvePath::resolve_path (AST::PathInExpression &expr) if (in_middle_of_path && segment.is_lower_self_seg ()) { rust_error_at (segment.get_locus (), ErrorCode::E0433, - "failed to resolve: %qs in paths can only be used " - "in start position", + "%qs in paths can only be used in start position", segment.as_string ().c_str ()); return UNKNOWN_NODEID; } @@ -75,8 +79,16 @@ ResolvePath::resolve_path (AST::PathInExpression &expr) // what is the current crate scope node id? module_scope_id = crate_scope_id; previous_resolved_node_id = module_scope_id; - resolver->insert_resolved_name (segment.get_node_id (), - module_scope_id); + + NodeId existing = UNKNOWN_NODEID; + bool ok = resolver->lookup_resolved_name (segment.get_node_id (), + &existing); + + if (ok) + rust_assert (existing == module_scope_id); + else + resolver->insert_resolved_name (segment.get_node_id (), + module_scope_id); continue; } else if (segment.is_super_path_seg ()) @@ -90,8 +102,16 @@ ResolvePath::resolve_path (AST::PathInExpression &expr) module_scope_id = resolver->peek_parent_module_scope (); previous_resolved_node_id = module_scope_id; - resolver->insert_resolved_name (segment.get_node_id (), - module_scope_id); + + NodeId existing = UNKNOWN_NODEID; + bool ok = resolver->lookup_resolved_name (segment.get_node_id (), + &existing); + + if (ok) + rust_assert (existing == module_scope_id); + else + resolver->insert_resolved_name (segment.get_node_id (), + module_scope_id); continue; } @@ -135,23 +155,45 @@ ResolvePath::resolve_path (AST::PathInExpression &expr) ident_seg.as_string ()); if (resolver->get_name_scope ().lookup (path, &resolved_node)) { - resolver->insert_resolved_name (segment.get_node_id (), - resolved_node); + NodeId existing = UNKNOWN_NODEID; + bool ok = resolver->lookup_resolved_name (segment.get_node_id (), + &existing); + + if (ok) + rust_assert (existing == resolved_node); + else + resolver->insert_resolved_name (segment.get_node_id (), + resolved_node); resolved_node_id = resolved_node; } // check the type scope else if (resolver->get_type_scope ().lookup (path, &resolved_node)) { - resolver->insert_resolved_type (segment.get_node_id (), - resolved_node); + NodeId existing = UNKNOWN_NODEID; + bool ok = resolver->lookup_resolved_type (segment.get_node_id (), + &existing); + + if (ok) + rust_assert (existing == resolved_node); + else + resolver->insert_resolved_type (segment.get_node_id (), + resolved_node); resolved_node_id = resolved_node; } else if (segment.is_lower_self_seg ()) { module_scope_id = crate_scope_id; previous_resolved_node_id = module_scope_id; - resolver->insert_resolved_name (segment.get_node_id (), - module_scope_id); + + NodeId existing = UNKNOWN_NODEID; + bool ok = resolver->lookup_resolved_name (segment.get_node_id (), + &existing); + + if (ok) + rust_assert (existing == module_scope_id); + else + resolver->insert_resolved_name (segment.get_node_id (), + module_scope_id); continue; } else @@ -174,20 +216,38 @@ ResolvePath::resolve_path (AST::PathInExpression &expr) resolved_node)) { resolved_node_id = resolved_node; - resolver->insert_resolved_name (segment.get_node_id (), - resolved_node); + + NodeId existing = UNKNOWN_NODEID; + bool ok + = resolver->lookup_resolved_name (segment.get_node_id (), + &existing); + + if (ok) + rust_assert (existing == resolved_node); + else + resolver->insert_resolved_name (segment.get_node_id (), + resolved_node); } else if (resolver->get_type_scope ().decl_was_declared_here ( resolved_node)) { resolved_node_id = resolved_node; - resolver->insert_resolved_type (segment.get_node_id (), - resolved_node); + + NodeId existing = UNKNOWN_NODEID; + bool ok + = resolver->lookup_resolved_type (segment.get_node_id (), + &existing); + + if (ok) + rust_assert (existing == resolved_node); + else + resolver->insert_resolved_type (segment.get_node_id (), + resolved_node); } else { rust_error_at (segment.get_locus (), - "Cannot find path %qs in this scope", + "Cannot find path %<%s%> in this scope", segment.as_string ().c_str ()); return UNKNOWN_NODEID; } @@ -207,7 +267,7 @@ ResolvePath::resolve_path (AST::PathInExpression &expr) else if (is_first_segment) { rust_error_at (segment.get_locus (), ErrorCode::E0433, - "Cannot find path %qs in this scope", + "Cannot find path %<%s%> in this scope", segment.as_string ().c_str ()); return UNKNOWN_NODEID; } @@ -219,15 +279,29 @@ ResolvePath::resolve_path (AST::PathInExpression &expr) // name scope first if (resolver->get_name_scope ().decl_was_declared_here (resolved_node_id)) { - resolver->insert_resolved_name (expr.get_node_id (), - resolved_node_id); + NodeId existing = UNKNOWN_NODEID; + bool ok + = resolver->lookup_resolved_name (expr.get_node_id (), &existing); + + if (ok) + rust_assert (existing == resolved_node_id); + else + resolver->insert_resolved_name (expr.get_node_id (), + resolved_node_id); } // check the type scope else if (resolver->get_type_scope ().decl_was_declared_here ( resolved_node_id)) { - resolver->insert_resolved_type (expr.get_node_id (), - resolved_node_id); + NodeId existing = UNKNOWN_NODEID; + bool ok + = resolver->lookup_resolved_type (expr.get_node_id (), &existing); + + if (ok) + rust_assert (existing == resolved_node_id); + else + resolver->insert_resolved_type (expr.get_node_id (), + resolved_node_id); } else { @@ -279,14 +353,29 @@ ResolvePath::resolve_path (AST::SimplePath &expr) // what is the current crate scope node id? module_scope_id = crate_scope_id; previous_resolved_node_id = module_scope_id; - resolver->insert_resolved_name (segment.get_node_id (), - module_scope_id); + + NodeId existing = UNKNOWN_NODEID; + bool ok = resolver->lookup_resolved_name (segment.get_node_id (), + &existing); + + if (ok) + rust_assert (existing == module_scope_id); + else + resolver->insert_resolved_name (segment.get_node_id (), + module_scope_id); resolved_node_id = module_scope_id; continue; } else if (segment.is_super_path_seg ()) { + if (!is_first_segment) + { + rust_error_at ( + segment.get_locus (), ErrorCode::E0433, + "%<super%> in paths can only be used in start position"); + return UNKNOWN_NODEID; + } if (module_scope_id == crate_scope_id) { rust_error_at (segment.get_locus (), @@ -296,8 +385,16 @@ ResolvePath::resolve_path (AST::SimplePath &expr) module_scope_id = resolver->peek_parent_module_scope (); previous_resolved_node_id = module_scope_id; - resolver->insert_resolved_name (segment.get_node_id (), - module_scope_id); + + NodeId existing = UNKNOWN_NODEID; + bool ok = resolver->lookup_resolved_name (segment.get_node_id (), + &existing); + + if (ok) + rust_assert (existing == module_scope_id); + else + resolver->insert_resolved_name (segment.get_node_id (), + module_scope_id); resolved_node_id = module_scope_id; continue; @@ -313,20 +410,36 @@ ResolvePath::resolve_path (AST::SimplePath &expr) resolved_node)) { resolved_node_id = resolved_node; - resolver->insert_resolved_name (segment.get_node_id (), - resolved_node); + + NodeId existing = UNKNOWN_NODEID; + bool ok = resolver->lookup_resolved_name (segment.get_node_id (), + &existing); + + if (ok) + rust_assert (existing == resolved_node); + else + resolver->insert_resolved_name (segment.get_node_id (), + resolved_node); } else if (resolver->get_type_scope ().decl_was_declared_here ( resolved_node)) { resolved_node_id = resolved_node; - resolver->insert_resolved_type (segment.get_node_id (), - resolved_node); + + NodeId existing = UNKNOWN_NODEID; + bool ok = resolver->lookup_resolved_type (segment.get_node_id (), + &existing); + + if (ok) + rust_assert (existing == resolved_node); + else + resolver->insert_resolved_type (segment.get_node_id (), + resolved_node); } else { rust_error_at (segment.get_locus (), - "Cannot find path %qs in this scope", + "Cannot find path %<%s%> in this scope", segment.as_string ().c_str ()); return UNKNOWN_NODEID; } @@ -342,15 +455,31 @@ ResolvePath::resolve_path (AST::SimplePath &expr) if (resolver->get_name_scope ().lookup (path, &resolved_node)) { resolved_node_id = resolved_node; - resolver->insert_resolved_name (segment.get_node_id (), - resolved_node); + + NodeId existing = UNKNOWN_NODEID; + bool ok = resolver->lookup_resolved_name (segment.get_node_id (), + &existing); + + if (ok) + rust_assert (existing == resolved_node); + else + resolver->insert_resolved_name (segment.get_node_id (), + resolved_node); } // check the type scope else if (resolver->get_type_scope ().lookup (path, &resolved_node)) { resolved_node_id = resolved_node; - resolver->insert_resolved_type (segment.get_node_id (), - resolved_node); + + NodeId existing = UNKNOWN_NODEID; + bool ok = resolver->lookup_resolved_type (segment.get_node_id (), + &existing); + + if (ok) + rust_assert (existing == resolved_node); + else + resolver->insert_resolved_type (segment.get_node_id (), + resolved_node); } } @@ -374,7 +503,7 @@ ResolvePath::resolve_path (AST::SimplePath &expr) if (resolved_node_id == UNKNOWN_NODEID) { rust_error_at (segment.get_locus (), - "cannot find simple path segment %qs in this scope", + "cannot find simple path segment %<%s%> in this scope", segment.as_string ().c_str ()); return UNKNOWN_NODEID; } @@ -393,15 +522,29 @@ ResolvePath::resolve_path (AST::SimplePath &expr) // name scope first if (resolver->get_name_scope ().decl_was_declared_here (resolved_node_id)) { - resolver->insert_resolved_name (expr.get_node_id (), - resolved_node_id); + NodeId existing = UNKNOWN_NODEID; + bool ok + = resolver->lookup_resolved_name (expr.get_node_id (), &existing); + + if (ok) + rust_assert (existing == resolved_node_id); + else + resolver->insert_resolved_name (expr.get_node_id (), + resolved_node_id); } // check the type scope else if (resolver->get_type_scope ().decl_was_declared_here ( resolved_node_id)) { - resolver->insert_resolved_type (expr.get_node_id (), - resolved_node_id); + NodeId existing = UNKNOWN_NODEID; + bool ok + = resolver->lookup_resolved_type (expr.get_node_id (), &existing); + + if (ok) + rust_assert (existing == resolved_node_id); + else + resolver->insert_resolved_type (expr.get_node_id (), + resolved_node_id); } else { diff --git a/gcc/rust/resolve/rust-ast-resolve-pattern.cc b/gcc/rust/resolve/rust-ast-resolve-pattern.cc index 9b383b7..ee84be8 100644 --- a/gcc/rust/resolve/rust-ast-resolve-pattern.cc +++ b/gcc/rust/resolve/rust-ast-resolve-pattern.cc @@ -330,7 +330,8 @@ PatternDeclaration::check_bindings_consistency ( if (!ident_is_outer_bound && !missing_bindings.count (ident)) missing_bindings.insert ({ident, inner_info}); - else if (outer_bindings_map[ident] != inner_info + else if (outer_bindings_map.count (ident) + && outer_bindings_map[ident] != inner_info && !inconsistent_bindings.count (ident)) inconsistent_bindings.insert ({ident, inner_info}); } diff --git a/gcc/rust/resolve/rust-ast-resolve-stmt.cc b/gcc/rust/resolve/rust-ast-resolve-stmt.cc index 2885291..bfba302 100644 --- a/gcc/rust/resolve/rust-ast-resolve-stmt.cc +++ b/gcc/rust/resolve/rust-ast-resolve-stmt.cc @@ -56,5 +56,26 @@ ResolveStmt::visit (AST::TraitImpl &impl_block) ResolveItem::go (impl_block, prefix, canonical_prefix); } +void +ResolveStmt::visit (AST::StaticItem &var) +{ + auto decl = CanonicalPath::new_seg (var.get_node_id (), + var.get_identifier ().as_string ()); + auto path = decl; + auto cpath = canonical_prefix.append (decl); + mappings.insert_canonical_path (var.get_node_id (), cpath); + + resolver->get_name_scope ().insert ( + path, var.get_node_id (), var.get_locus (), false, Rib::ItemType::Static, + [&] (const CanonicalPath &, NodeId, location_t locus) -> void { + rich_location r (line_table, var.get_locus ()); + r.add_range (locus); + redefined_error (r); + }); + + ResolveType::go (var.get_type ()); + ResolveExpr::go (var.get_expr (), path, cpath); +} + } // namespace Resolver } // namespace Rust diff --git a/gcc/rust/resolve/rust-ast-resolve-stmt.h b/gcc/rust/resolve/rust-ast-resolve-stmt.h index 8e64a76..d413a7c 100644 --- a/gcc/rust/resolve/rust-ast-resolve-stmt.h +++ b/gcc/rust/resolve/rust-ast-resolve-stmt.h @@ -63,7 +63,7 @@ public: [&] (const CanonicalPath &, NodeId, location_t locus) -> void { rich_location r (line_table, constant.get_locus ()); r.add_range (locus); - rust_error_at (r, "redefined multiple times"); + redefined_error (r); }); ResolveType::go (constant.get_type ()); @@ -73,9 +73,10 @@ public: void visit (AST::LetStmt &stmt) override { if (stmt.has_init_expr ()) - { - ResolveExpr::go (stmt.get_init_expr (), prefix, canonical_prefix); - } + ResolveExpr::go (stmt.get_init_expr (), prefix, canonical_prefix); + + if (stmt.has_else_expr ()) + ResolveExpr::go (stmt.get_else_expr (), prefix, canonical_prefix); PatternDeclaration::go (stmt.get_pattern (), Rib::ItemType::Var); if (stmt.has_type ()) @@ -97,17 +98,15 @@ public: [&] (const CanonicalPath &, NodeId, location_t locus) -> void { rich_location r (line_table, struct_decl.get_locus ()); r.add_range (locus); - rust_error_at (r, "redefined multiple times"); + redefined_error (r); }); NodeId scope_node_id = struct_decl.get_node_id (); resolver->get_type_scope ().push (scope_node_id); if (struct_decl.has_generics ()) - { - for (auto &generic : struct_decl.get_generic_params ()) - ResolveGenericParam::go (*generic, prefix, canonical_prefix); - } + ResolveGenericParams::go (struct_decl.get_generic_params (), prefix, + canonical_prefix); for (AST::TupleField &field : struct_decl.get_fields ()) ResolveType::go (field.get_field_type ()); @@ -130,17 +129,15 @@ public: [&] (const CanonicalPath &, NodeId, location_t locus) -> void { rich_location r (line_table, enum_decl.get_locus ()); r.add_range (locus); - rust_error_at (r, "redefined multiple times"); + redefined_error (r); }); NodeId scope_node_id = enum_decl.get_node_id (); resolver->get_type_scope ().push (scope_node_id); if (enum_decl.has_generics ()) - { - for (auto &generic : enum_decl.get_generic_params ()) - ResolveGenericParam::go (*generic, prefix, canonical_prefix); - } + ResolveGenericParams::go (enum_decl.get_generic_params (), prefix, + canonical_prefix); for (auto &variant : enum_decl.get_variants ()) ResolveStmt::go (*variant, path, canonical_prefix, path); @@ -162,7 +159,7 @@ public: [&] (const CanonicalPath &, NodeId, location_t locus) -> void { rich_location r (line_table, item.get_locus ()); r.add_range (locus); - rust_error_at (r, "redefined multiple times"); + redefined_error (r); }); // Done, no fields. @@ -182,7 +179,7 @@ public: [&] (const CanonicalPath &, NodeId, location_t locus) -> void { rich_location r (line_table, item.get_locus ()); r.add_range (locus); - rust_error_at (r, "redefined multiple times"); + redefined_error (r); }); for (auto &field : item.get_tuple_fields ()) @@ -208,7 +205,7 @@ public: [&] (const CanonicalPath &, NodeId, location_t locus) -> void { rich_location r (line_table, item.get_locus ()); r.add_range (locus); - rust_error_at (r, "redefined multiple times"); + redefined_error (r); }); for (auto &field : item.get_struct_fields ()) @@ -234,7 +231,7 @@ public: [&] (const CanonicalPath &, NodeId, location_t locus) -> void { rich_location r (line_table, item.get_locus ()); r.add_range (locus); - rust_error_at (r, "redefined multiple times"); + redefined_error (r); }); // Done, no fields. @@ -255,17 +252,15 @@ public: [&] (const CanonicalPath &, NodeId, location_t locus) -> void { rich_location r (line_table, struct_decl.get_locus ()); r.add_range (locus); - rust_error_at (r, "redefined multiple times"); + redefined_error (r); }); NodeId scope_node_id = struct_decl.get_node_id (); resolver->get_type_scope ().push (scope_node_id); if (struct_decl.has_generics ()) - { - for (auto &generic : struct_decl.get_generic_params ()) - ResolveGenericParam::go (*generic, prefix, canonical_prefix); - } + ResolveGenericParams::go (struct_decl.get_generic_params (), prefix, + canonical_prefix); for (AST::StructField &field : struct_decl.get_fields ()) { @@ -293,15 +288,15 @@ public: [&] (const CanonicalPath &, NodeId, location_t locus) -> void { rich_location r (line_table, union_decl.get_locus ()); r.add_range (locus); - rust_error_at (r, "redefined multiple times"); + redefined_error (r); }); NodeId scope_node_id = union_decl.get_node_id (); resolver->get_type_scope ().push (scope_node_id); if (union_decl.has_generics ()) - for (auto &generic : union_decl.get_generic_params ()) - ResolveGenericParam::go (*generic, prefix, canonical_prefix); + ResolveGenericParams::go (union_decl.get_generic_params (), prefix, + canonical_prefix); for (AST::StructField &field : union_decl.get_variants ()) { @@ -329,7 +324,7 @@ public: [&] (const CanonicalPath &, NodeId, location_t locus) -> void { rich_location r (line_table, function.get_locus ()); r.add_range (locus); - rust_error_at (r, "redefined multiple times"); + redefined_error (r); }); NodeId scope_node_id = function.get_node_id (); @@ -338,11 +333,11 @@ public: resolver->get_label_scope ().push (scope_node_id); resolver->push_new_name_rib (resolver->get_name_scope ().peek ()); resolver->push_new_type_rib (resolver->get_type_scope ().peek ()); - resolver->push_new_label_rib (resolver->get_type_scope ().peek ()); + resolver->push_new_label_rib (resolver->get_label_scope ().peek ()); if (function.has_generics ()) - for (auto &generic : function.get_generic_params ()) - ResolveGenericParam::go (*generic, prefix, canonical_prefix); + ResolveGenericParams::go (function.get_generic_params (), prefix, + canonical_prefix); if (function.has_return_type ()) ResolveType::go (function.get_return_type ()); @@ -388,6 +383,7 @@ public: void visit (AST::Trait &trait) override; void visit (AST::InherentImpl &impl_block) override; void visit (AST::TraitImpl &impl_block) override; + void visit (AST::StaticItem &var) override; private: ResolveStmt (const CanonicalPath &prefix, diff --git a/gcc/rust/resolve/rust-ast-resolve-toplevel.h b/gcc/rust/resolve/rust-ast-resolve-toplevel.h index 565ca92..f52fb8a 100644 --- a/gcc/rust/resolve/rust-ast-resolve-toplevel.h +++ b/gcc/rust/resolve/rust-ast-resolve-toplevel.h @@ -58,7 +58,7 @@ public: [&] (const CanonicalPath &, NodeId, location_t locus) -> void { rich_location r (line_table, module.get_locus ()); r.add_range (locus); - rust_error_at (r, "redefined multiple times"); + redefined_error (r); }); NodeId current_module = resolver->peek_current_module_scope (); @@ -88,7 +88,7 @@ public: [&] (const CanonicalPath &, NodeId, location_t locus) -> void { rich_location r (line_table, alias.get_locus ()); r.add_range (locus); - rust_error_at (r, "redefined multiple times"); + redefined_error (r); }); NodeId current_module = resolver->peek_current_module_scope (); @@ -110,7 +110,7 @@ public: [&] (const CanonicalPath &, NodeId, location_t locus) -> void { rich_location r (line_table, struct_decl.get_locus ()); r.add_range (locus); - rust_error_at (r, "redefined multiple times"); + redefined_error (r); }); NodeId current_module = resolver->peek_current_module_scope (); @@ -132,7 +132,7 @@ public: [&] (const CanonicalPath &, NodeId, location_t locus) -> void { rich_location r (line_table, enum_decl.get_locus ()); r.add_range (locus); - rust_error_at (r, "redefined multiple times"); + redefined_error (r); }); resolver->push_new_module_scope (enum_decl.get_node_id ()); @@ -158,7 +158,7 @@ public: [&] (const CanonicalPath &, NodeId, location_t locus) -> void { rich_location r (line_table, item.get_locus ()); r.add_range (locus); - rust_error_at (r, "redefined multiple times"); + redefined_error (r); }); mappings.insert_canonical_path (item.get_node_id (), cpath); @@ -180,7 +180,7 @@ public: [&] (const CanonicalPath &, NodeId, location_t locus) -> void { rich_location r (line_table, item.get_locus ()); r.add_range (locus); - rust_error_at (r, "redefined multiple times"); + redefined_error (r); }); mappings.insert_canonical_path (item.get_node_id (), cpath); @@ -202,7 +202,7 @@ public: [&] (const CanonicalPath &, NodeId, location_t locus) -> void { rich_location r (line_table, item.get_locus ()); r.add_range (locus); - rust_error_at (r, "redefined multiple times"); + redefined_error (r); }); mappings.insert_canonical_path (item.get_node_id (), cpath); @@ -224,7 +224,7 @@ public: [&] (const CanonicalPath &, NodeId, location_t locus) -> void { rich_location r (line_table, item.get_locus ()); r.add_range (locus); - rust_error_at (r, "redefined multiple times"); + redefined_error (r); }); mappings.insert_canonical_path (item.get_node_id (), cpath); @@ -242,14 +242,21 @@ public: auto path = prefix.append (decl); auto cpath = canonical_prefix.append (decl); - resolver->get_type_scope ().insert ( - path, struct_decl.get_node_id (), struct_decl.get_locus (), false, - Rib::ItemType::Type, - [&] (const CanonicalPath &, NodeId, location_t locus) -> void { - rich_location r (line_table, struct_decl.get_locus ()); - r.add_range (locus); - rust_error_at (r, "redefined multiple times"); - }); + auto duplicate_item + = [&] (const CanonicalPath &, NodeId, location_t locus) -> void { + rich_location r (line_table, struct_decl.get_locus ()); + r.add_range (locus); + redefined_error (r); + }; + + resolver->get_type_scope ().insert (path, struct_decl.get_node_id (), + struct_decl.get_locus (), false, + Rib::ItemType::Type, duplicate_item); + + if (struct_decl.is_unit_struct ()) + resolver->get_name_scope ().insert (path, struct_decl.get_node_id (), + struct_decl.get_locus (), false, + Rib::ItemType::Type, duplicate_item); NodeId current_module = resolver->peek_current_module_scope (); mappings.insert_module_child_item (current_module, decl); @@ -270,7 +277,7 @@ public: [&] (const CanonicalPath &, NodeId, location_t locus) -> void { rich_location r (line_table, union_decl.get_locus ()); r.add_range (locus); - rust_error_at (r, "redefined multiple times"); + redefined_error (r); }); NodeId current_module = resolver->peek_current_module_scope (); @@ -290,7 +297,7 @@ public: [&] (const CanonicalPath &, NodeId, location_t locus) -> void { rich_location r (line_table, var.get_locus ()); r.add_range (locus); - rust_error_at (r, "redefined multiple times"); + redefined_error (r); }); NodeId current_module = resolver->peek_current_module_scope (); @@ -311,7 +318,7 @@ public: [&] (const CanonicalPath &, NodeId, location_t locus) -> void { rich_location r (line_table, constant.get_locus ()); r.add_range (locus); - rust_error_at (r, "redefined multiple times"); + redefined_error (r); }); NodeId current_module = resolver->peek_current_module_scope (); @@ -333,7 +340,7 @@ public: [&] (const CanonicalPath &, NodeId, location_t locus) -> void { rich_location r (line_table, function.get_locus ()); r.add_range (locus); - rust_error_at (r, "redefined multiple times"); + redefined_error (r); }); NodeId current_module = resolver->peek_current_module_scope (); @@ -381,7 +388,7 @@ public: [&] (const CanonicalPath &, NodeId, location_t locus) -> void { rich_location r (line_table, impl_block.get_locus ()); r.add_range (locus); - rust_error_at (r, "redefined multiple times"); + redefined_error (r); }); for (auto &impl_item : impl_block.get_impl_items ()) @@ -401,7 +408,7 @@ public: [&] (const CanonicalPath &, NodeId, location_t locus) -> void { rich_location r (line_table, trait.get_locus ()); r.add_range (locus); - rust_error_at (r, "redefined multiple times"); + redefined_error (r); }); for (auto &item : trait.get_trait_items ()) @@ -473,7 +480,7 @@ public: [&] (const CanonicalPath &, NodeId, location_t locus) -> void { rich_location r (line_table, extern_crate.get_locus ()); r.add_range (locus); - rust_error_at (r, "redefined multiple times"); + redefined_error (r); }); } diff --git a/gcc/rust/resolve/rust-ast-resolve-type.cc b/gcc/rust/resolve/rust-ast-resolve-type.cc index 934d6ea..8fd69c3 100644 --- a/gcc/rust/resolve/rust-ast-resolve-type.cc +++ b/gcc/rust/resolve/rust-ast-resolve-type.cc @@ -18,12 +18,58 @@ #include "rust-ast-resolve-type.h" #include "rust-ast-resolve-expr.h" +#include "rust-canonical-path.h" +#include "rust-type.h" +#include "rust-hir-map.h" namespace Rust { namespace Resolver { // rust-ast-resolve-type.h +NodeId +ResolveType::go (AST::Type &type) +{ + ResolveType resolver; + type.accept_vis (resolver); + return resolver.resolved_node; +} + +void +ResolveType::visit (AST::BareFunctionType &fntype) +{ + for (auto ¶m : fntype.get_function_params ()) + ResolveType::go (param.get_type ()); + + if (fntype.has_return_type ()) + ResolveType::go (fntype.get_return_type ()); +} + +void +ResolveType::visit (AST::TupleType &tuple) +{ + if (tuple.is_unit_type ()) + { + resolved_node = resolver->get_unit_type_node_id (); + return; + } + + for (auto &elem : tuple.get_elems ()) + ResolveType::go (*elem); +} + +void +ResolveType::visit (AST::TypePath &path) +{ + ResolveRelativeTypePath::go (path, resolved_node); +} + +void +ResolveType::visit (AST::QualifiedPathInType &path) +{ + ResolveRelativeQualTypePath::go (path); +} + void ResolveType::visit (AST::ArrayType &type) { @@ -49,6 +95,12 @@ ResolveType::visit (AST::TraitObjectType &type) } void +ResolveType::visit (AST::ParenthesisedType &type) +{ + resolved_node = ResolveType::go (*type.get_type_in_parens ()); +} + +void ResolveType::visit (AST::ReferenceType &type) { resolved_node = ResolveType::go (type.get_type_referenced ()); @@ -63,13 +115,13 @@ ResolveType::visit (AST::RawPointerType &type) void ResolveType::visit (AST::InferredType &) { - // FIXME + // nothing to do } void ResolveType::visit (AST::NeverType &) { - // FIXME + resolved_node = resolver->get_never_type_node_id (); } void @@ -78,6 +130,19 @@ ResolveType::visit (AST::SliceType &type) resolved_node = ResolveType::go (type.get_elem_type ()); } +void +ResolveType::visit (AST::ImplTraitType &type) +{ + for (auto &bound : type.get_type_param_bounds ()) + ResolveTypeBound::go (*bound); +} + +void +ResolveType::visit (AST::ImplTraitTypeOneBound &type) +{ + ResolveTypeBound::go (type.get_trait_bound ()); +} + // resolve relative type-paths bool @@ -91,45 +156,56 @@ ResolveRelativeTypePath::go (AST::TypePath &path, NodeId &resolved_node_id) for (size_t i = 0; i < path.get_segments ().size (); i++) { auto &segment = path.get_segments ().at (i); - const AST::PathIdentSegment &ident_seg = segment->get_ident_segment (); bool is_first_segment = i == 0; - resolved_node_id = UNKNOWN_NODEID; + NodeId crate_scope_id = resolver->peek_crate_module_scope (); + auto ident_string = segment->is_lang_item () + ? LangItem::PrettyString (segment->get_lang_item ()) + : segment->get_ident_segment ().as_string (); - bool in_middle_of_path = i > 0; - if (in_middle_of_path && segment->is_lower_self_seg ()) - { - rust_error_at (segment->get_locus (), ErrorCode::E0433, - "failed to resolve: %qs in paths can only be used " - "in start position", - segment->as_string ().c_str ()); - return false; - } + resolved_node_id = UNKNOWN_NODEID; - NodeId crate_scope_id = resolver->peek_crate_module_scope (); - if (segment->is_crate_path_seg ()) + if (segment->is_lang_item ()) { - // what is the current crate scope node id? - module_scope_id = crate_scope_id; - previous_resolved_node_id = module_scope_id; - resolver->insert_resolved_name (segment->get_node_id (), - module_scope_id); - - continue; + resolved_node_id = Analysis::Mappings::get ().get_lang_item_node ( + segment->get_lang_item ()); + previous_resolved_node_id = resolved_node_id; } - else if (segment->is_super_path_seg ()) + else { - if (module_scope_id == crate_scope_id) + bool in_middle_of_path = i > 0; + if (in_middle_of_path && segment->is_lower_self_seg ()) { - rust_error_at (segment->get_locus (), - "cannot use super at the crate scope"); + rust_error_at (segment->get_locus (), ErrorCode::E0433, + "%qs in paths can only be used in start position", + segment->as_string ().c_str ()); return false; } - module_scope_id = resolver->peek_parent_module_scope (); - previous_resolved_node_id = module_scope_id; - resolver->insert_resolved_name (segment->get_node_id (), - module_scope_id); - continue; + if (segment->is_crate_path_seg ()) + { + // what is the current crate scope node id? + module_scope_id = crate_scope_id; + previous_resolved_node_id = module_scope_id; + resolver->insert_resolved_name (segment->get_node_id (), + module_scope_id); + + continue; + } + else if (segment->is_super_path_seg ()) + { + if (module_scope_id == crate_scope_id) + { + rust_error_at (segment->get_locus (), + "cannot use super at the crate scope"); + return false; + } + + module_scope_id = resolver->peek_parent_module_scope (); + previous_resolved_node_id = module_scope_id; + resolver->insert_resolved_name (segment->get_node_id (), + module_scope_id); + continue; + } } switch (segment->get_type ()) @@ -169,27 +245,48 @@ ResolveRelativeTypePath::go (AST::TypePath &path, NodeId &resolved_node_id) // name scope first NodeId resolved_node = UNKNOWN_NODEID; const CanonicalPath path - = CanonicalPath::new_seg (segment->get_node_id (), - ident_seg.as_string ()); + = CanonicalPath::new_seg (segment->get_node_id (), ident_string); if (resolver->get_type_scope ().lookup (path, &resolved_node)) { - resolver->insert_resolved_type (segment->get_node_id (), - resolved_node); + NodeId existing = UNKNOWN_NODEID; + bool ok = resolver->lookup_resolved_type (segment->get_node_id (), + &existing); + + if (ok) + rust_assert (existing == resolved_node); + else + resolver->insert_resolved_type (segment->get_node_id (), + resolved_node); resolved_node_id = resolved_node; } else if (resolver->get_name_scope ().lookup (path, &resolved_node)) { - resolver->insert_resolved_name (segment->get_node_id (), - resolved_node); + NodeId existing = UNKNOWN_NODEID; + bool ok = resolver->lookup_resolved_name (segment->get_node_id (), + &existing); + + if (ok) + rust_assert (existing == resolved_node); + else + resolver->insert_resolved_name (segment->get_node_id (), + resolved_node); resolved_node_id = resolved_node; } - else if (segment->is_lower_self_seg ()) + else if (!segment->is_lang_item () && segment->is_lower_self_seg ()) { // what is the current crate scope node id? module_scope_id = crate_scope_id; previous_resolved_node_id = module_scope_id; - resolver->insert_resolved_name (segment->get_node_id (), - module_scope_id); + + NodeId existing = UNKNOWN_NODEID; + bool ok = resolver->lookup_resolved_name (segment->get_node_id (), + &existing); + + if (ok) + rust_assert (existing == module_scope_id); + else + resolver->insert_resolved_name (segment->get_node_id (), + module_scope_id); continue; } @@ -199,8 +296,7 @@ ResolveRelativeTypePath::go (AST::TypePath &path, NodeId &resolved_node_id) && previous_resolved_node_id == module_scope_id) { tl::optional<CanonicalPath &> resolved_child - = mappings.lookup_module_child (module_scope_id, - ident_seg.as_string ()); + = mappings.lookup_module_child (module_scope_id, ident_string); if (resolved_child.has_value ()) { NodeId resolved_node = resolved_child->get_node_id (); @@ -208,15 +304,33 @@ ResolveRelativeTypePath::go (AST::TypePath &path, NodeId &resolved_node_id) resolved_node)) { resolved_node_id = resolved_node; - resolver->insert_resolved_name (segment->get_node_id (), - resolved_node); + + NodeId existing = UNKNOWN_NODEID; + bool ok + = resolver->lookup_resolved_name (segment->get_node_id (), + &existing); + + if (ok) + rust_assert (existing == resolved_node); + else + resolver->insert_resolved_name (segment->get_node_id (), + resolved_node); } else if (resolver->get_type_scope ().decl_was_declared_here ( resolved_node)) { resolved_node_id = resolved_node; - resolver->insert_resolved_type (segment->get_node_id (), - resolved_node); + + NodeId existing = UNKNOWN_NODEID; + bool ok + = resolver->lookup_resolved_type (segment->get_node_id (), + &existing); + + if (ok) + rust_assert (existing == resolved_node); + else + resolver->insert_resolved_type (segment->get_node_id (), + resolved_node); } else { @@ -241,8 +355,8 @@ ResolveRelativeTypePath::go (AST::TypePath &path, NodeId &resolved_node_id) else if (is_first_segment) { rust_error_at (segment->get_locus (), ErrorCode::E0412, - "failed to resolve TypePath: %s in this scope", - segment->as_string ().c_str ()); + "could not resolve type path %qs", + segment->get_ident_segment ().as_string ().c_str ()); return false; } } @@ -252,15 +366,29 @@ ResolveRelativeTypePath::go (AST::TypePath &path, NodeId &resolved_node_id) // name scope first if (resolver->get_name_scope ().decl_was_declared_here (resolved_node_id)) { - resolver->insert_resolved_name (path.get_node_id (), - resolved_node_id); + NodeId existing = UNKNOWN_NODEID; + bool ok + = resolver->lookup_resolved_name (path.get_node_id (), &existing); + + if (ok) + rust_assert (existing == resolved_node_id); + else + resolver->insert_resolved_name (path.get_node_id (), + resolved_node_id); } // check the type scope else if (resolver->get_type_scope ().decl_was_declared_here ( resolved_node_id)) { - resolver->insert_resolved_type (path.get_node_id (), - resolved_node_id); + NodeId existing = UNKNOWN_NODEID; + bool ok + = resolver->lookup_resolved_type (path.get_node_id (), &existing); + + if (ok) + rust_assert (existing == resolved_node_id); + else + resolver->insert_resolved_type (path.get_node_id (), + resolved_node_id); } else { @@ -495,10 +623,74 @@ ResolveTypeToCanonicalPath::visit (AST::TraitObjectTypeOneBound &type) } void -ResolveTypeToCanonicalPath::visit (AST::TraitObjectType &) +ResolveTypeToCanonicalPath::visit (AST::TraitObjectType &type) { - // FIXME is this actually allowed? dyn A+B - rust_unreachable (); + rust_assert (!type.get_type_param_bounds ().empty ()); + + auto &first_bound = type.get_type_param_bounds ().front (); + + // Is it allowed or even possible to have a lifetime bound as a first bound? + if (first_bound->get_bound_type () == AST::TraitBound::LIFETIME) + rust_unreachable (); + + auto &trait = static_cast<AST::TraitBound &> (*first_bound); + + CanonicalPath path = CanonicalPath::create_empty (); + bool ok = ResolveTypeToCanonicalPath::go (trait.get_type_path (), path); + + // right? + rust_assert (ok); + + auto slice_path = "<dyn " + path.get (); + + for (size_t idx = 1; idx < type.get_type_param_bounds ().size (); idx++) + { + auto &additional_bound = type.get_type_param_bounds ()[idx]; + + std::string str; + + switch (additional_bound->get_bound_type ()) + { + case AST::TypeParamBound::TRAIT: { + auto bound_path = CanonicalPath::create_empty (); + + auto &bound_type_path + = static_cast<AST::TraitBound &> (*additional_bound) + .get_type_path (); + bool ok + = ResolveTypeToCanonicalPath::go (bound_type_path, bound_path); + + if (!ok) + continue; + + str = bound_path.get (); + break; + } + case AST::TypeParamBound::LIFETIME: + rust_unreachable (); + break; + } + slice_path += " + " + str; + } + + slice_path += ">"; + + result = CanonicalPath::new_seg (type.get_node_id (), slice_path); +} + +void +ResolveTypeToCanonicalPath::visit (AST::NeverType &type) +{ + result = CanonicalPath::new_seg (type.get_node_id (), "!"); +} + +void +ResolveTypeToCanonicalPath::visit (AST::TupleType &type) +{ + if (!type.is_unit_type ()) + rust_unreachable (); + + result = CanonicalPath::new_seg (type.get_node_id (), "()"); } ResolveTypeToCanonicalPath::ResolveTypeToCanonicalPath () diff --git a/gcc/rust/resolve/rust-ast-resolve-type.h b/gcc/rust/resolve/rust-ast-resolve-type.h index 0076424..f1481fc 100644 --- a/gcc/rust/resolve/rust-ast-resolve-type.h +++ b/gcc/rust/resolve/rust-ast-resolve-type.h @@ -21,6 +21,11 @@ #include "rust-ast-resolve-base.h" #include "rust-ast-resolve-expr.h" +#include "rust-diagnostics.h" +#include "rust-hir-map.h" +#include "rust-path.h" +#include "rust-type.h" +#include "util/rust-hir-map.h" namespace Rust { namespace Resolver { @@ -56,59 +61,23 @@ class ResolveType : public ResolverBase using Rust::Resolver::ResolverBase::visit; public: - static NodeId go (AST::Type &type) - { - ResolveType resolver; - type.accept_vis (resolver); - return resolver.resolved_node; - } - - void visit (AST::BareFunctionType &fntype) override - { - for (auto ¶m : fntype.get_function_params ()) - ResolveType::go (param.get_type ()); - - if (fntype.has_return_type ()) - ResolveType::go (fntype.get_return_type ()); - } - - void visit (AST::TupleType &tuple) override - { - if (tuple.is_unit_type ()) - { - resolved_node = resolver->get_unit_type_node_id (); - return; - } - - for (auto &elem : tuple.get_elems ()) - ResolveType::go (*elem); - } - - void visit (AST::TypePath &path) override - { - ResolveRelativeTypePath::go (path, resolved_node); - } - - void visit (AST::QualifiedPathInType &path) override - { - ResolveRelativeQualTypePath::go (path); - } + static NodeId go (AST::Type &type); + void visit (AST::BareFunctionType &fntype) override; + void visit (AST::TupleType &tuple) override; + void visit (AST::TypePath &path) override; + void visit (AST::QualifiedPathInType &path) override; void visit (AST::ArrayType &type) override; - void visit (AST::ReferenceType &type) override; - void visit (AST::InferredType &type) override; - void visit (AST::NeverType &type) override; - void visit (AST::RawPointerType &type) override; - void visit (AST::TraitObjectTypeOneBound &type) override; - void visit (AST::TraitObjectType &type) override; - + void visit (AST::ParenthesisedType &type) override; void visit (AST::SliceType &type) override; + void visit (AST::ImplTraitType &type) override; + void visit (AST::ImplTraitTypeOneBound &type) override; private: ResolveType () : ResolverBase () {} @@ -135,66 +104,83 @@ private: ResolveTypeBound () : ResolverBase () {} }; -class ResolveGenericParam : public ResolverBase +class ResolveGenericParams : public ResolverBase { using Rust::Resolver::ResolverBase::visit; public: - static NodeId go (AST::GenericParam ¶m, const CanonicalPath &prefix, - const CanonicalPath &canonical_prefix) + static void go (std::vector<std::unique_ptr<AST::GenericParam>> ¶ms, + const CanonicalPath &prefix, + const CanonicalPath &canonical_prefix) { - ResolveGenericParam resolver (prefix, canonical_prefix); - param.accept_vis (resolver); - return resolver.resolved_node; + ResolveGenericParams resolver (prefix, canonical_prefix); + + // this needs to be done in two phases as they can be used and defined later + // in bounds + for (auto ¶m : params) + param->accept_vis (resolver); + + resolver.first_pass = false; + + for (auto ¶m : params) + param->accept_vis (resolver); } - void visit (AST::ConstGenericParam ¶m) override + static void go_single (AST::GenericParam ¶m, const CanonicalPath &prefix, + const CanonicalPath &canonical_prefix) { - ResolveType::go (param.get_type ()); - - if (param.has_default_value ()) - ResolveExpr::go (param.get_default_value ().get_expression (), prefix, - canonical_prefix); + ResolveGenericParams resolver (prefix, canonical_prefix); - ok = true; + param.accept_vis (resolver); + resolver.first_pass = false; + param.accept_vis (resolver); } - void visit (AST::TypeParam ¶m) override + void visit (AST::ConstGenericParam ¶m) override { - // if it has a type lets resolve it - if (param.has_type ()) + if (first_pass) ResolveType::go (param.get_type ()); + else if (param.has_default_value ()) + ResolveExpr::go (param.get_default_value_unchecked ().get_expression (), + prefix, canonical_prefix); + } - if (param.has_type_param_bounds ()) + void visit (AST::TypeParam ¶m) override + { + if (first_pass) + { + // if it has a type lets resolve it + if (param.has_type ()) + ResolveType::go (param.get_type ()); + + auto seg = CanonicalPath::new_seg ( + param.get_node_id (), param.get_type_representation ().as_string ()); + resolver->get_type_scope ().insert ( + seg, param.get_node_id (), param.get_locus (), false, + Rib::ItemType::Type, + [&] (const CanonicalPath &, NodeId, location_t locus) -> void { + rust_error_at (param.get_locus (), + "generic param defined multiple times"); + rust_error_at (locus, "was defined here"); + }); + + mappings.insert_canonical_path (param.get_node_id (), seg); + } + else if (param.has_type_param_bounds ()) { for (auto &bound : param.get_type_param_bounds ()) - { - ResolveTypeBound::go (*bound); - } + ResolveTypeBound::go (*bound); } - - auto seg - = CanonicalPath::new_seg (param.get_node_id (), - param.get_type_representation ().as_string ()); - resolver->get_type_scope ().insert ( - seg, param.get_node_id (), param.get_locus (), false, Rib::ItemType::Type, - [&] (const CanonicalPath &, NodeId, location_t locus) -> void { - rust_error_at (param.get_locus (), - "generic param redefined multiple times"); - rust_error_at (locus, "was defined here"); - }); - - mappings.insert_canonical_path (param.get_node_id (), seg); } private: - ResolveGenericParam (const CanonicalPath &prefix, - const CanonicalPath &canonical_prefix) - : ResolverBase (), ok (false), prefix (prefix), + ResolveGenericParams (const CanonicalPath &prefix, + const CanonicalPath &canonical_prefix) + : ResolverBase (), first_pass (true), prefix (prefix), canonical_prefix (canonical_prefix) {} - bool ok; + bool first_pass; const CanonicalPath &prefix; const CanonicalPath &canonical_prefix; }; @@ -246,6 +232,10 @@ public: void visit (AST::TraitObjectType &type) override; + void visit (AST::NeverType &type) override; + + void visit (AST::TupleType &type) override; + private: ResolveTypeToCanonicalPath (); diff --git a/gcc/rust/resolve/rust-ast-resolve.cc b/gcc/rust/resolve/rust-ast-resolve.cc index a467d1e..3e3c992 100644 --- a/gcc/rust/resolve/rust-ast-resolve.cc +++ b/gcc/rust/resolve/rust-ast-resolve.cc @@ -63,7 +63,10 @@ NameResolution::go (AST::Crate &crate) { // lookup current crate name CrateNum cnum = mappings.get_current_crate (); - const auto &crate_name = mappings.get_crate_name (cnum).value (); + + // Clones the crate name instead of references due to gcc's possibly + // dangling references warnings + const auto crate_name = mappings.get_crate_name (cnum).value (); // setup the ribs NodeId scope_node_id = crate.get_node_id (); @@ -72,7 +75,7 @@ NameResolution::go (AST::Crate &crate) resolver->get_label_scope ().push (scope_node_id); resolver->push_new_name_rib (resolver->get_name_scope ().peek ()); resolver->push_new_type_rib (resolver->get_type_scope ().peek ()); - resolver->push_new_label_rib (resolver->get_type_scope ().peek ()); + resolver->push_new_label_rib (resolver->get_label_scope ().peek ()); // get the root segment CanonicalPath crate_prefix diff --git a/gcc/rust/resolve/rust-default-resolver.cc b/gcc/rust/resolve/rust-default-resolver.cc index 6de694f..480034c 100644 --- a/gcc/rust/resolve/rust-default-resolver.cc +++ b/gcc/rust/resolve/rust-default-resolver.cc @@ -30,13 +30,7 @@ DefaultResolver::visit (AST::BlockExpr &expr) // extracting the lambda from the `scoped` call otherwise the code looks like // a hot turd thanks to our .clang-format - auto inner_fn = [this, &expr] () { - for (auto &stmt : expr.get_statements ()) - stmt->accept_vis (*this); - - if (expr.has_tail_expr ()) - expr.get_tail_expr ().accept_vis (*this); - }; + auto inner_fn = [this, &expr] () { AST::DefaultASTVisitor::visit (expr); }; ctx.scoped (Rib::Kind::Normal, expr.get_node_id (), inner_fn); } @@ -44,10 +38,7 @@ DefaultResolver::visit (AST::BlockExpr &expr) void DefaultResolver::visit (AST::Module &module) { - auto item_fn = [this, &module] () { - for (auto &item : module.get_items ()) - item->accept_vis (*this); - }; + auto item_fn = [this, &module] () { AST::DefaultASTVisitor::visit (module); }; ctx.scoped (Rib::Kind::Module, module.get_node_id (), item_fn, module.get_name ()); @@ -56,35 +47,8 @@ DefaultResolver::visit (AST::Module &module) void DefaultResolver::visit (AST::Function &function) { - auto def_fn = [this, &function] () { - for (auto &p : function.get_function_params ()) - { - if (p->is_variadic ()) - { - auto ¶m = static_cast<AST::VariadicParam &> (*p); - if (param.has_pattern ()) - param.get_pattern ().accept_vis (*this); - } - else if (p->is_self ()) - { - auto ¶m = static_cast<AST::SelfParam &> (*p); - param.get_type ().accept_vis (*this); - param.get_lifetime ().accept_vis (*this); - } - else - { - auto ¶m = static_cast<AST::FunctionParam &> (*p); - param.get_pattern ().accept_vis (*this); - param.get_type ().accept_vis (*this); - } - } - - if (function.has_return_type ()) - visit (function.get_return_type ()); - - if (function.has_body ()) - function.get_definition ().value ()->accept_vis (*this); - }; + auto def_fn + = [this, &function] () { AST::DefaultASTVisitor::visit (function); }; ctx.scoped (Rib::Kind::Function, function.get_node_id (), def_fn); } @@ -92,20 +56,14 @@ DefaultResolver::visit (AST::Function &function) void DefaultResolver::visit (AST::ForLoopExpr &expr) { - ctx.scoped (Rib::Kind::Normal, expr.get_node_id (), [this, &expr] () { - expr.get_pattern ().accept_vis (*this); - expr.get_iterator_expr ().accept_vis (*this); - expr.get_loop_block ().accept_vis (*this); - }); + ctx.scoped (Rib::Kind::Normal, expr.get_node_id (), + [this, &expr] () { AST::DefaultASTVisitor::visit (expr); }); } void DefaultResolver::visit (AST::Trait &trait) { - auto inner_fn = [this, &trait] () { - for (auto &item : trait.get_trait_items ()) - item->accept_vis (*this); - }; + auto inner_fn = [this, &trait] () { AST::DefaultASTVisitor::visit (trait); }; ctx.scoped (Rib::Kind::TraitOrImpl, trait.get_node_id (), inner_fn, trait.get_identifier () /* FIXME: Is that valid?*/); @@ -114,11 +72,7 @@ DefaultResolver::visit (AST::Trait &trait) void DefaultResolver::visit (AST::InherentImpl &impl) { - auto inner_fn = [this, &impl] () { - visit (impl.get_type ()); - for (auto &item : impl.get_impl_items ()) - item->accept_vis (*this); - }; + auto inner_fn = [this, &impl] () { AST::DefaultASTVisitor::visit (impl); }; ctx.scoped (Rib::Kind::TraitOrImpl, impl.get_node_id (), inner_fn); } @@ -126,10 +80,7 @@ DefaultResolver::visit (AST::InherentImpl &impl) void DefaultResolver::visit (AST::TraitImpl &impl) { - auto inner_fn = [this, &impl] () { - for (auto &item : impl.get_impl_items ()) - item->accept_vis (*this); - }; + auto inner_fn = [this, &impl] () { AST::DefaultASTVisitor::visit (impl); }; ctx.scoped (Rib::Kind::TraitOrImpl, impl.get_node_id (), inner_fn); } @@ -137,343 +88,73 @@ DefaultResolver::visit (AST::TraitImpl &impl) void DefaultResolver::visit (AST::StructStruct &type) { - // do we need to scope anything here? no, right? - - // we also can't visit `StructField`s by default, so there's nothing to do - - // correct? or should we do something like + auto inner_fn = [this, &type] () { AST::DefaultASTVisitor::visit (type); }; - AST::DefaultASTVisitor::visit (type); - - // FIXME: ??? + ctx.scoped (Rib::Kind::Item /* FIXME: Correct? */, type.get_node_id (), + inner_fn, type.get_struct_name ()); } void -DefaultResolver::visit (AST::Enum &type) +DefaultResolver::visit (AST::TupleStruct &type) { - // FIXME: Do we need to scope anything by default? - - auto variant_fn = [this, &type] () { - for (auto &variant : type.get_variants ()) - variant->accept_vis (*this); - }; + auto inner_fn = [this, &type] () { AST::DefaultASTVisitor::visit (type); }; ctx.scoped (Rib::Kind::Item /* FIXME: Correct? */, type.get_node_id (), - variant_fn, type.get_identifier ()); + inner_fn, type.get_struct_name ()); } void -DefaultResolver::visit (AST::StructExprFieldIdentifierValue &) -{} - -void -DefaultResolver::visit (AST::StructExprFieldIndexValue &) -{} - -void -DefaultResolver::visit (AST::ClosureExprInner &expr) +DefaultResolver::visit (AST::Enum &type) { - if (expr.is_marked_for_strip ()) - return; + auto variant_fn = [this, &type] () { AST::DefaultASTVisitor::visit (type); }; - for (auto ¶m : expr.get_params ()) - { - if (param.is_error ()) - continue; - - param.get_pattern ().accept_vis (*this); - if (param.has_type_given ()) - param.get_type ().accept_vis (*this); - } - - expr.get_definition_expr ().accept_vis (*this); + ctx.scoped (Rib::Kind::Item /* FIXME: Correct? */, type.get_node_id (), + variant_fn, type.get_identifier ()); } void -DefaultResolver::visit (AST::ClosureExprInnerTyped &expr) +DefaultResolver::visit (AST::Union &type) { - if (expr.is_marked_for_strip ()) - return; - - for (auto ¶m : expr.get_params ()) - { - if (param.is_error ()) - continue; + auto inner_fn = [this, &type] () { AST::DefaultASTVisitor::visit (type); }; - param.get_pattern ().accept_vis (*this); - if (param.has_type_given ()) - param.get_type ().accept_vis (*this); - } - - expr.get_definition_block ().accept_vis (*this); - expr.get_return_type ().accept_vis (*this); + ctx.scoped (Rib::Kind::Item /* FIXME: Correct? */, type.get_node_id (), + inner_fn, type.get_identifier ()); } void -DefaultResolver::visit (AST::ContinueExpr &expr) -{} - -void -DefaultResolver::visit (AST::RangeFromToExpr &expr) -{} - -void -DefaultResolver::visit (AST::RangeFromExpr &expr) -{} - -void -DefaultResolver::visit (AST::RangeToExpr &expr) -{} - -void -DefaultResolver::visit (AST::RangeFromToInclExpr &expr) -{} - -void -DefaultResolver::visit (AST::RangeToInclExpr &expr) -{} - -void -DefaultResolver::visit (AST::ReturnExpr &expr) -{} - -void -DefaultResolver::visit (AST::CallExpr &expr) +DefaultResolver::visit (AST::TypeAlias &type) { - expr.get_function_expr ().accept_vis (*this); + auto inner_fn = [this, &type] () { AST::DefaultASTVisitor::visit (type); }; - for (auto ¶m : expr.get_params ()) - param->accept_vis (*this); + ctx.scoped (Rib::Kind::Item /* FIXME: Correct? */, type.get_node_id (), + inner_fn, type.get_new_type_name ()); } void -DefaultResolver::visit (AST::MethodCallExpr &expr) +DefaultResolver::visit (AST::ClosureExprInner &expr) { - expr.get_receiver_expr ().accept_vis (*this); - - if (expr.get_method_name ().has_generic_args ()) - { - auto &args = expr.get_method_name ().get_generic_args (); - for (auto &arg : args.get_generic_args ()) - arg.accept_vis (*this); - for (auto &arg : args.get_binding_args ()) - if (!arg.is_error ()) - arg.get_type ().accept_vis (*this); - for (auto &arg : args.get_lifetime_args ()) - arg.accept_vis (*this); - } + if (expr.is_marked_for_strip ()) + return; - for (auto ¶m : expr.get_params ()) - param->accept_vis (*this); + AST::DefaultASTVisitor::visit (expr); } void -DefaultResolver::visit (AST::LoopExpr &expr) -{} - -void -DefaultResolver::visit (AST::WhileLoopExpr &expr) -{} - -void -DefaultResolver::visit (AST::WhileLetLoopExpr &expr) -{} - -void -DefaultResolver::visit (AST::IfExpr &expr) +DefaultResolver::visit (AST::ClosureExprInnerTyped &expr) { - expr.get_condition_expr ().accept_vis (*this); - expr.get_if_block ().accept_vis (*this); -} + if (expr.is_marked_for_strip ()) + return; -void -DefaultResolver::visit (AST::IfExprConseqElse &expr) -{ - expr.get_condition_expr ().accept_vis (*this); - expr.get_if_block ().accept_vis (*this); - expr.get_else_block ().accept_vis (*this); + AST::DefaultASTVisitor::visit (expr); } void -DefaultResolver::visit (AST::IfLetExpr &expr) -{} - -void -DefaultResolver::visit (AST::IfLetExprConseqElse &) -{} - -void DefaultResolver::visit (AST::MatchExpr &expr) { if (expr.is_marked_for_strip ()) return; - expr.get_scrutinee_expr ().accept_vis (*this); - for (auto &arm : expr.get_match_cases ()) - { - arm.get_expr ().accept_vis (*this); - for (auto &pat : arm.get_arm ().get_patterns ()) - pat->accept_vis (*this); - if (arm.get_arm ().has_match_arm_guard ()) - arm.get_arm ().get_guard_expr ().accept_vis (*this); - } -} - -void -DefaultResolver::visit (AST::AwaitExpr &expr) -{} - -void -DefaultResolver::visit (AST::AsyncBlockExpr &expr) -{} - -void -DefaultResolver::visit (AST::DelimTokenTree &) -{} - -void -DefaultResolver::visit (AST::AttrInputMetaItemContainer &) -{} - -void -DefaultResolver::visit (AST::IdentifierExpr &expr) -{} - -void -DefaultResolver::visit (AST::LifetimeParam &) -{} - -void -DefaultResolver::visit (AST::ConstGenericParam &) -{} - -void -DefaultResolver::visit (AST::PathInExpression &expr) -{ - for (auto &seg : expr.get_segments ()) - if (seg.has_generic_args ()) - { - auto &args = seg.get_generic_args (); - for (auto &arg : args.get_generic_args ()) - arg.accept_vis (*this); - for (auto &arg : args.get_binding_args ()) - if (!arg.is_error ()) - arg.get_type ().accept_vis (*this); - for (auto &arg : args.get_lifetime_args ()) - arg.accept_vis (*this); - } -} - -void -DefaultResolver::visit (AST::TypePathSegmentGeneric &) -{} - -void -DefaultResolver::visit (AST::TypePathSegmentFunction &) -{} - -void -DefaultResolver::visit (AST::TypePath &) -{} - -void -DefaultResolver::visit (AST::QualifiedPathInExpression &) -{} - -void -DefaultResolver::visit (AST::QualifiedPathInType &) -{} - -void -DefaultResolver::visit (AST::LiteralExpr &expr) -{} - -void -DefaultResolver::visit (AST::AttrInputLiteral &) -{} - -void -DefaultResolver::visit (AST::AttrInputMacro &) -{} - -void -DefaultResolver::visit (AST::MetaItemLitExpr &expr) -{} - -void -DefaultResolver::visit (AST::MetaItemPathLit &) -{} - -void -DefaultResolver::visit (AST::StructExprStruct &) -{} - -void -DefaultResolver::visit (AST::StructExprStructFields &) -{} - -void -DefaultResolver::visit (AST::StructExprStructBase &) -{} - -void -DefaultResolver::visit (AST::TypeParam &) -{} - -void -DefaultResolver::visit (AST::LifetimeWhereClauseItem &) -{} - -void -DefaultResolver::visit (AST::TypeBoundWhereClauseItem &) -{} - -void -DefaultResolver::visit (AST::ExternCrate &) -{} - -void -DefaultResolver::visit (AST::UseTreeGlob &) -{} - -void -DefaultResolver::visit (AST::UseTreeList &) -{} - -void -DefaultResolver::visit (AST::UseTreeRebind &) -{} - -void -DefaultResolver::visit (AST::UseDeclaration &) -{} - -void -DefaultResolver::visit (AST::TypeAlias &) -{} - -void -DefaultResolver::visit (AST::EnumItem &) -{} - -void -DefaultResolver::visit (AST::EnumItemTuple &item) -{ - for (auto &field : item.get_tuple_fields ()) - field.get_field_type ().accept_vis (*this); -} - -void -DefaultResolver::visit (AST::EnumItemStruct &item) -{ - for (auto &field : item.get_struct_fields ()) - field.get_field_type ().accept_vis (*this); -} - -void -DefaultResolver::visit (AST::EnumItemDiscriminant &item) -{ - if (item.has_expr ()) - item.get_expr ().accept_vis (*this); + AST::DefaultASTVisitor::visit (expr); } void @@ -481,10 +162,8 @@ DefaultResolver::visit (AST::ConstantItem &item) { if (item.has_expr ()) { - auto expr_vis = [this, &item] () { - item.get_expr ().accept_vis (*this); - visit (item.get_type ()); - }; + auto expr_vis + = [this, &item] () { AST::DefaultASTVisitor::visit (item); }; // FIXME: Why do we need a Rib here? ctx.scoped (Rib::Kind::ConstantItem, item.get_node_id (), expr_vis); @@ -494,187 +173,19 @@ DefaultResolver::visit (AST::ConstantItem &item) void DefaultResolver::visit (AST::StaticItem &item) { - auto expr_vis = [this, &item] () { item.get_expr ().accept_vis (*this); }; + auto expr_vis = [this, &item] () { AST::DefaultASTVisitor::visit (item); }; // FIXME: Why do we need a Rib here? ctx.scoped (Rib::Kind::ConstantItem, item.get_node_id (), expr_vis); } void -DefaultResolver::visit (AST::TraitItemConst &) -{} - -void -DefaultResolver::visit (AST::TraitItemType &) -{} - -void -DefaultResolver::visit (AST::ExternalTypeItem &) -{} - -void -DefaultResolver::visit (AST::ExternalStaticItem &) -{} - -void -DefaultResolver::visit (AST::MacroMatchRepetition &) -{} - -void -DefaultResolver::visit (AST::MacroMatcher &) -{} - -void -DefaultResolver::visit (AST::MacroRulesDefinition &) -{} - -void -DefaultResolver::visit (AST::MacroInvocation &) -{} - -void -DefaultResolver::visit (AST::MetaItemPath &) -{} - -void -DefaultResolver::visit (AST::MetaItemSeq &) -{} - -void -DefaultResolver::visit (AST::MetaListPaths &) -{} - -void -DefaultResolver::visit (AST::MetaListNameValueStr &) -{} - -void -DefaultResolver::visit (AST::RangePatternBoundPath &) -{} - -void -DefaultResolver::visit (AST::RangePatternBoundQualPath &) -{} - -void -DefaultResolver::visit (AST::RangePattern &) -{} - -void -DefaultResolver::visit (AST::ReferencePattern &) -{} - -void -DefaultResolver::visit (AST::StructPatternFieldTuplePat &) -{} - -void -DefaultResolver::visit (AST::StructPatternFieldIdentPat &) -{} - -void -DefaultResolver::visit (AST::StructPatternFieldIdent &) -{} - -void -DefaultResolver::visit (AST::StructPattern &) -{} - -void -DefaultResolver::visit (AST::TupleStructItemsNoRange &) -{} - -void -DefaultResolver::visit (AST::TupleStructItemsRange &) -{} - -void -DefaultResolver::visit (AST::TupleStructPattern &) -{} - -void -DefaultResolver::visit (AST::TuplePatternItemsMultiple &) -{} - -void -DefaultResolver::visit (AST::TuplePatternItemsRanged &) -{} - -void -DefaultResolver::visit (AST::TuplePattern &) -{} - -void -DefaultResolver::visit (AST::GroupedPattern &) -{} - -void -DefaultResolver::visit (AST::SlicePattern &) -{} - -void -DefaultResolver::visit (AST::AltPattern &) -{} - -void -DefaultResolver::visit (AST::EmptyStmt &) -{} - -void -DefaultResolver::visit (AST::TraitBound &) -{} - -void -DefaultResolver::visit (AST::ImplTraitType &) -{} - -void -DefaultResolver::visit (AST::TraitObjectType &) -{} - -void -DefaultResolver::visit (AST::ParenthesisedType &) -{} - -void -DefaultResolver::visit (AST::ImplTraitTypeOneBound &) -{} - -void -DefaultResolver::visit (AST::TraitObjectTypeOneBound &) -{} - -void -DefaultResolver::visit (AST::TupleType &) -{} - -void -DefaultResolver::visit (AST::ReferenceType &) -{} - -void -DefaultResolver::visit (AST::ArrayType &) -{} - -void -DefaultResolver::visit (AST::SliceType &) -{} - -void -DefaultResolver::visit (AST::BareFunctionType &) -{} - -void -DefaultResolver::visit (AST::SelfParam &) -{} - -void -DefaultResolver::visit (AST::FunctionParam &) -{} +DefaultResolver::visit (AST::TypeParam ¶m) +{ + auto expr_vis = [this, ¶m] () { AST::DefaultASTVisitor::visit (param); }; -void -DefaultResolver::visit (AST::VariadicParam &) -{} + ctx.scoped (Rib::Kind::ForwardTypeParamBan, param.get_node_id (), expr_vis); +} } // namespace Resolver2_0 } // namespace Rust diff --git a/gcc/rust/resolve/rust-default-resolver.h b/gcc/rust/resolve/rust-default-resolver.h index 6bca8b7..2a987ef 100644 --- a/gcc/rust/resolve/rust-default-resolver.h +++ b/gcc/rust/resolve/rust-default-resolver.h @@ -42,122 +42,31 @@ public: // First, our lexical scope expressions - these visit their sub nodes, always // these nodes create new scopes and ribs - they are often used to declare new // variables, such as a for loop's iterator, or a function's arguments - void visit (AST::BlockExpr &); - void visit (AST::Module &); - void visit (AST::Function &); - void visit (AST::ForLoopExpr &); - void visit (AST::Trait &); - void visit (AST::InherentImpl &); - void visit (AST::TraitImpl &); + void visit (AST::BlockExpr &) override; + void visit (AST::Module &) override; + void visit (AST::Function &) override; + void visit (AST::ForLoopExpr &expr) override; + void visit (AST::Trait &) override; + void visit (AST::InherentImpl &) override; + void visit (AST::TraitImpl &) override; + + void visit (AST::TypeParam &) override; // type dec nodes, which visit their fields or variants by default - void visit (AST::StructStruct &); - void visit (AST::Enum &); + void visit (AST::StructStruct &) override; + void visit (AST::TupleStruct &) override; + void visit (AST::Enum &) override; + void visit (AST::Union &) override; + void visit (AST::TypeAlias &) override; // Visitors that visit their expression node(s) - void visit (AST::StructExprFieldIdentifierValue &); - void visit (AST::StructExprFieldIndexValue &); - void visit (AST::ClosureExprInner &); - void visit (AST::ClosureExprInnerTyped &); - void visit (AST::ContinueExpr &); - void visit (AST::RangeFromToExpr &); - void visit (AST::RangeFromExpr &); - void visit (AST::RangeToExpr &); - void visit (AST::RangeFromToInclExpr &); - void visit (AST::RangeToInclExpr &); - void visit (AST::ReturnExpr &); - void visit (AST::CallExpr &); - void visit (AST::MethodCallExpr &); - void visit (AST::LoopExpr &); - void visit (AST::WhileLoopExpr &); - void visit (AST::WhileLetLoopExpr &); - void visit (AST::IfExpr &); - void visit (AST::IfExprConseqElse &); - void visit (AST::IfLetExpr &); - void visit (AST::IfLetExprConseqElse &); - void visit (AST::MatchExpr &); - void visit (AST::AwaitExpr &); - void visit (AST::AsyncBlockExpr &); + void visit (AST::ClosureExprInner &) override; + void visit (AST::ClosureExprInnerTyped &) override; + void visit (AST::MatchExpr &) override; // Leaf visitors, which do nothing by default - void visit (AST::DelimTokenTree &); - void visit (AST::AttrInputMetaItemContainer &); - void visit (AST::IdentifierExpr &); - void visit (AST::LifetimeParam &); - void visit (AST::ConstGenericParam &); - void visit (AST::PathInExpression &); - void visit (AST::TypePathSegmentGeneric &); - void visit (AST::TypePathSegmentFunction &); - void visit (AST::TypePath &); - void visit (AST::QualifiedPathInExpression &); - void visit (AST::QualifiedPathInType &); - void visit (AST::LiteralExpr &); - void visit (AST::AttrInputLiteral &); - void visit (AST::AttrInputMacro &); - void visit (AST::MetaItemLitExpr &); - void visit (AST::MetaItemPathLit &); - void visit (AST::StructExprStruct &); - void visit (AST::StructExprStructFields &); - void visit (AST::StructExprStructBase &); - void visit (AST::TypeParam &); - void visit (AST::LifetimeWhereClauseItem &); - void visit (AST::TypeBoundWhereClauseItem &); - void visit (AST::ExternCrate &); - void visit (AST::UseTreeGlob &); - void visit (AST::UseTreeList &); - void visit (AST::UseTreeRebind &); - void visit (AST::UseDeclaration &); - void visit (AST::TypeAlias &); - void visit (AST::EnumItem &); - void visit (AST::EnumItemTuple &); - void visit (AST::EnumItemStruct &); - void visit (AST::EnumItemDiscriminant &); - void visit (AST::ConstantItem &); - void visit (AST::StaticItem &); - void visit (AST::TraitItemConst &); - void visit (AST::TraitItemType &); - void visit (AST::ExternalTypeItem &); - void visit (AST::ExternalStaticItem &); - void visit (AST::MacroMatchRepetition &); - void visit (AST::MacroMatcher &); - void visit (AST::MacroRulesDefinition &); - void visit (AST::MacroInvocation &); - void visit (AST::MetaItemPath &); - void visit (AST::MetaItemSeq &); - void visit (AST::MetaListPaths &); - void visit (AST::MetaListNameValueStr &); - void visit (AST::RangePatternBoundPath &); - void visit (AST::RangePatternBoundQualPath &); - void visit (AST::RangePattern &); - void visit (AST::ReferencePattern &); - void visit (AST::StructPatternFieldTuplePat &); - void visit (AST::StructPatternFieldIdentPat &); - void visit (AST::StructPatternFieldIdent &); - void visit (AST::StructPattern &); - void visit (AST::TupleStructItemsNoRange &); - void visit (AST::TupleStructItemsRange &); - void visit (AST::TupleStructPattern &); - void visit (AST::TuplePatternItemsMultiple &); - void visit (AST::TuplePatternItemsRanged &); - void visit (AST::TuplePattern &); - void visit (AST::GroupedPattern &); - void visit (AST::SlicePattern &); - void visit (AST::AltPattern &); - void visit (AST::EmptyStmt &); - void visit (AST::TraitBound &); - void visit (AST::ImplTraitType &); - void visit (AST::TraitObjectType &); - void visit (AST::ParenthesisedType &); - void visit (AST::ImplTraitTypeOneBound &); - void visit (AST::TraitObjectTypeOneBound &); - void visit (AST::TupleType &); - void visit (AST::ReferenceType &); - void visit (AST::ArrayType &); - void visit (AST::SliceType &); - void visit (AST::BareFunctionType &); - void visit (AST::FunctionParam &); - void visit (AST::VariadicParam &); - void visit (AST::SelfParam &); + void visit (AST::ConstantItem &) override; + void visit (AST::StaticItem &) override; protected: DefaultResolver (NameResolutionContext &ctx) : ctx (ctx) {} diff --git a/gcc/rust/resolve/rust-early-name-resolver-2.0.cc b/gcc/rust/resolve/rust-early-name-resolver-2.0.cc index 1b21e11..3390f09 100644 --- a/gcc/rust/resolve/rust-early-name-resolver-2.0.cc +++ b/gcc/rust/resolve/rust-early-name-resolver-2.0.cc @@ -18,13 +18,18 @@ #include "rust-early-name-resolver-2.0.h" #include "rust-ast-full.h" +#include "rust-diagnostics.h" #include "rust-toplevel-name-resolver-2.0.h" #include "rust-attributes.h" +#include "rust-finalize-imports-2.0.h" +#include "rust-attribute-values.h" namespace Rust { namespace Resolver2_0 { -Early::Early (NameResolutionContext &ctx) : DefaultResolver (ctx) {} +Early::Early (NameResolutionContext &ctx) + : DefaultResolver (ctx), toplevel (TopLevel (ctx)), dirty (false) +{} void Early::insert_once (AST::MacroInvocation &invocation, NodeId resolved) @@ -48,19 +53,117 @@ void Early::go (AST::Crate &crate) { // First we go through TopLevel resolution to get all our declared items - auto toplevel = TopLevel (ctx); toplevel.go (crate); - textual_scope.push (); + // We start with resolving the list of imports that `TopLevel` has built for + // us - // Then we proceed to the proper "early" name resolution: Import and macro - // name resolution + dirty = toplevel.is_dirty (); + // We now proceed with resolving macros, which can be nested in almost any + // items + textual_scope.push (); for (auto &item : crate.items) item->accept_vis (*this); - textual_scope.pop (); } +bool +Early::resolve_glob_import (NodeId use_dec_id, TopLevel::ImportKind &&glob) +{ + auto resolved = ctx.resolve_path (glob.to_resolve, Namespace::Types); + if (!resolved.has_value ()) + return false; + + auto result + = Analysis::Mappings::get ().lookup_ast_module (resolved->get_node_id ()); + if (!result) + return false; + + // here, we insert the module's NodeId into the import_mappings and will look + // up the module proper in `FinalizeImports` + // The namespace does not matter here since we are dealing with a glob + // TODO: Ugly + import_mappings.insert (use_dec_id, + ImportPair (std::move (glob), + ImportData::Glob (*resolved))); + + return true; +} + +bool +Early::resolve_simple_import (NodeId use_dec_id, TopLevel::ImportKind &&import) +{ + auto definitions = resolve_path_in_all_ns (import.to_resolve); + + // if we've found at least one definition, then we're good + if (definitions.empty ()) + return false; + + auto &imports = import_mappings.new_or_access (use_dec_id); + + imports.emplace_back ( + ImportPair (std::move (import), + ImportData::Simple (std::move (definitions)))); + + return true; +} + +bool +Early::resolve_rebind_import (NodeId use_dec_id, + TopLevel::ImportKind &&rebind_import) +{ + auto definitions = resolve_path_in_all_ns (rebind_import.to_resolve); + + // if we've found at least one definition, then we're good + if (definitions.empty ()) + return false; + + auto &imports = import_mappings.new_or_access (use_dec_id); + + imports.emplace_back ( + ImportPair (std::move (rebind_import), + ImportData::Rebind (std::move (definitions)))); + + return true; +} + +void +Early::build_import_mapping ( + std::pair<NodeId, std::vector<TopLevel::ImportKind>> &&use_import) +{ + auto found = false; + auto use_dec_id = use_import.first; + + for (auto &&import : use_import.second) + { + // We create a copy of the path in case of errors, since the `import` will + // be moved into the newly created import mappings + auto path = import.to_resolve; + + // used to skip the "unresolved import" error + // if we output other errors during resolution + size_t old_error_count = macro_resolve_errors.size (); + + switch (import.kind) + { + case TopLevel::ImportKind::Kind::Glob: + found = resolve_glob_import (use_dec_id, std::move (import)); + break; + case TopLevel::ImportKind::Kind::Simple: + found = resolve_simple_import (use_dec_id, std::move (import)); + break; + case TopLevel::ImportKind::Kind::Rebind: + found = resolve_rebind_import (use_dec_id, std::move (import)); + break; + } + + if (!found && old_error_count == macro_resolve_errors.size ()) + collect_error (Error (path.get_final_segment ().get_locus (), + ErrorCode::E0433, "unresolved import %qs", + path.as_string ().c_str ())); + } +} + void Early::TextualScope::push () { @@ -123,11 +226,24 @@ Early::visit (AST::BlockExpr &block) void Early::visit (AST::Module &module) { - textual_scope.push (); + bool is_macro_use = false; + + for (const auto &attr : module.get_outer_attrs ()) + { + if (attr.get_path ().as_string () == Values::Attributes::MACRO_USE) + { + is_macro_use = true; + break; + } + } + + if (!is_macro_use) + textual_scope.push (); DefaultResolver::visit (module); - textual_scope.pop (); + if (!is_macro_use) + textual_scope.pop (); } void @@ -135,6 +251,10 @@ Early::visit (AST::MacroInvocation &invoc) { auto path = invoc.get_invoc_data ().get_path (); + if (invoc.get_kind () == AST::MacroInvocation::InvocKind::Builtin) + for (auto &pending_invoc : invoc.get_pending_eager_invocations ()) + pending_invoc->accept_vis (*this); + // When a macro is invoked by an unqualified identifier (not part of a // multi-part path), it is first looked up in textual scoping. If this does // not yield any results, then it is looked up in path-based scoping. If the @@ -152,13 +272,14 @@ Early::visit (AST::MacroInvocation &invoc) // we won't have changed `definition` from `nullopt` if there are more // than one segments in our path if (!definition.has_value ()) - definition = ctx.macros.resolve_path (path.get_segments ()); + definition = ctx.resolve_path (path.get_segments (), Namespace::Macros); // if the definition still does not have a value, then it's an error if (!definition.has_value ()) { collect_error (Error (invoc.get_locus (), ErrorCode::E0433, - "could not resolve macro invocation")); + "could not resolve macro invocation %qs", + path.as_string ().c_str ())); return; } @@ -193,36 +314,37 @@ Early::visit_attributes (std::vector<AST::Attribute> &attrs) auto traits = attr.get_traits_to_derive (); for (auto &trait : traits) { - auto definition - = ctx.macros.resolve_path (trait.get ().get_segments ()); + auto definition = ctx.resolve_path (trait.get ().get_segments (), + Namespace::Macros); if (!definition.has_value ()) { // FIXME: Change to proper error message - rust_error_at (trait.get ().get_locus (), - "could not resolve trait"); + collect_error (Error (trait.get ().get_locus (), + "could not resolve trait %qs", + trait.get ().as_string ().c_str ())); continue; } auto pm_def = mappings.lookup_derive_proc_macro_def ( definition->get_node_id ()); - rust_assert (pm_def.has_value ()); - - mappings.insert_derive_proc_macro_invocation (trait, - pm_def.value ()); + if (pm_def.has_value ()) + mappings.insert_derive_proc_macro_invocation (trait, + pm_def.value ()); } } else if (Analysis::BuiltinAttributeMappings::get () ->lookup_builtin (name) .is_error ()) // Do not resolve builtins { - auto definition - = ctx.macros.resolve_path (attr.get_path ().get_segments ()); + auto definition = ctx.resolve_path (attr.get_path ().get_segments (), + Namespace::Macros); if (!definition.has_value ()) { // FIXME: Change to proper error message - rust_error_at (attr.get_locus (), - "could not resolve attribute macro invocation"); + collect_error ( + Error (attr.get_locus (), + "could not resolve attribute macro invocation")); return; } auto pm_def = mappings.lookup_attribute_proc_macro_def ( @@ -250,5 +372,103 @@ Early::visit (AST::StructStruct &s) DefaultResolver::visit (s); } +void +Early::finalize_simple_import (const Early::ImportPair &mapping) +{ + // FIXME: We probably need to store namespace information + + auto locus = mapping.import_kind.to_resolve.get_locus (); + auto data = mapping.data; + auto identifier + = mapping.import_kind.to_resolve.get_final_segment ().get_segment_name (); + + for (auto &&definition : data.definitions ()) + toplevel + .insert_or_error_out ( + identifier, locus, definition.first.get_node_id (), definition.second /* TODO: This isn't clear - it would be better if it was called .ns or something */); +} + +void +Early::finalize_glob_import (NameResolutionContext &ctx, + const Early::ImportPair &mapping) +{ + auto module = Analysis::Mappings::get ().lookup_ast_module ( + mapping.data.module ().get_node_id ()); + rust_assert (module); + + GlobbingVisitor glob_visitor (ctx); + glob_visitor.go (module.value ()); +} + +void +Early::finalize_rebind_import (const Early::ImportPair &mapping) +{ + // We can fetch the value here as `resolve_rebind` will only be called on + // imports of the right kind + auto &path = mapping.import_kind.to_resolve; + auto &rebind = mapping.import_kind.rebind.value (); + auto data = mapping.data; + + location_t locus = UNKNOWN_LOCATION; + std::string declared_name; + + // FIXME: This needs to be done in `FinalizeImports` + switch (rebind.get_new_bind_type ()) + { + case AST::UseTreeRebind::NewBindType::IDENTIFIER: + declared_name = rebind.get_identifier ().as_string (); + locus = rebind.get_identifier ().get_locus (); + break; + case AST::UseTreeRebind::NewBindType::NONE: { + const auto &segments = path.get_segments (); + // We don't want to insert `self` with `use module::self` + if (path.get_final_segment ().is_lower_self_seg ()) + { + rust_assert (segments.size () > 1); + declared_name = segments[segments.size () - 2].as_string (); + } + else + declared_name = path.get_final_segment ().as_string (); + locus = path.get_final_segment ().get_locus (); + break; + } + case AST::UseTreeRebind::NewBindType::WILDCARD: + rust_unreachable (); + break; + } + + for (auto &&definition : data.definitions ()) + toplevel.insert_or_error_out ( + declared_name, locus, definition.first.get_node_id (), definition.second /* TODO: This isn't clear - it would be better if it was called .ns or something */); +} + +void +Early::visit (AST::UseDeclaration &decl) +{ + auto &imports = toplevel.get_imports_to_resolve (); + auto current_import = imports.find (decl.get_node_id ()); + if (current_import != imports.end ()) + { + build_import_mapping (*current_import); + } + + // Once this is done, we finalize their resolution + for (const auto &mapping : import_mappings.get (decl.get_node_id ())) + switch (mapping.import_kind.kind) + { + case TopLevel::ImportKind::Kind::Glob: + finalize_glob_import (ctx, mapping); + break; + case TopLevel::ImportKind::Kind::Simple: + finalize_simple_import (mapping); + break; + case TopLevel::ImportKind::Kind::Rebind: + finalize_rebind_import (mapping); + break; + } + + DefaultResolver::visit (decl); +} + } // namespace Resolver2_0 } // namespace Rust diff --git a/gcc/rust/resolve/rust-early-name-resolver-2.0.h b/gcc/rust/resolve/rust-early-name-resolver-2.0.h index 590a256..e78bec0 100644 --- a/gcc/rust/resolve/rust-early-name-resolver-2.0.h +++ b/gcc/rust/resolve/rust-early-name-resolver-2.0.h @@ -24,6 +24,8 @@ #include "rust-ast-visitor.h" #include "rust-name-resolution-context.h" #include "rust-default-resolver.h" +#include "rust-rib.h" +#include "rust-toplevel-name-resolver-2.0.h" namespace Rust { namespace Resolver2_0 { @@ -32,9 +34,14 @@ class Early : public DefaultResolver { using DefaultResolver::visit; + TopLevel toplevel; + bool dirty; + public: Early (NameResolutionContext &ctx); + bool is_dirty () { return dirty; } + void go (AST::Crate &crate); const std::vector<Error> &get_macro_resolve_errors () const @@ -53,6 +60,111 @@ public: void visit (AST::Function &) override; void visit (AST::StructStruct &) override; + void visit (AST::UseDeclaration &) override; + + struct ImportData + { + enum class Kind + { + Simple, + Glob, + Rebind + } kind; + + static ImportData + Simple (std::vector<std::pair<Rib::Definition, Namespace>> &&definitions) + { + return ImportData (Kind::Simple, std::move (definitions)); + } + + static ImportData + Rebind (std::vector<std::pair<Rib::Definition, Namespace>> &&definitions) + { + return ImportData (Kind::Rebind, std::move (definitions)); + } + + static ImportData Glob (Rib::Definition module) + { + return ImportData (Kind::Glob, module); + } + + Rib::Definition module () const + { + rust_assert (kind == Kind::Glob); + return glob_module; + } + + std::vector<std::pair<Rib::Definition, Namespace>> definitions () const + { + rust_assert (kind != Kind::Glob); + return std::move (resolved_definitions); + } + + private: + ImportData ( + Kind kind, + std::vector<std::pair<Rib::Definition, Namespace>> &&definitions) + : kind (kind), resolved_definitions (std::move (definitions)) + {} + + ImportData (Kind kind, Rib::Definition module) + : kind (kind), glob_module (module) + {} + + // TODO: Should this be a union? + + // For Simple and Rebind + std::vector<std::pair<Rib::Definition, Namespace>> resolved_definitions; + + // For Glob + Rib::Definition glob_module; + }; + + struct ImportPair + { + TopLevel::ImportKind import_kind; + ImportData data; + + explicit ImportPair (TopLevel::ImportKind &&kind, ImportData &&data) + : import_kind (std::move (kind)), data (std::move (data)) + {} + }; + + class ImportMappings + { + public: + std::vector<ImportPair> &new_or_access (NodeId path_id) + { + // We insert an empty vector, unless an element was already present for + // `use_dec_id` - which is returned in the tuple's first member + auto iter = mappings.insert ({{path_id}, {}}); + + // We then get that tuple's first member, which will be an iterator to the + // existing vec<pair<ImportKind, ImportData>> OR an iterator to our newly + // created empty vector (plus its key since this is a hashmap iterator). + // we then access the second member of the pair to get access to the + // vector directly. + return iter.first->second; + } + + void insert (NodeId path_id, std::vector<ImportPair> &&pairs) + { + mappings.insert ({{path_id}, std::move (pairs)}); + } + + // Same as `insert`, but with just one node + void insert (NodeId path_id, ImportPair &&pair) + { + mappings.insert ({{path_id}, {pair}}); + } + + std::vector<ImportPair> &get (NodeId use_id) { return mappings[use_id]; } + + private: + // Each path can import in multiple namespaces, hence the mapping from one + // path to a vector of import pairs + std::unordered_map<NodeId, std::vector<ImportPair>> mappings; + }; private: void visit_attributes (std::vector<AST::Attribute> &attrs); @@ -91,10 +203,66 @@ private: std::vector<std::unordered_map<std::string, NodeId>> scopes; }; + // Mappings between an import and the definition it imports + ImportMappings import_mappings; + + // FIXME: Documentation + // Call this on all the paths of a UseDec - so each flattened path in a + // UseTreeList for example + // FIXME: Should that return `found`? + bool resolve_simple_import (NodeId use_dec_id, TopLevel::ImportKind &&import); + bool resolve_glob_import (NodeId use_dec_id, TopLevel::ImportKind &&import); + bool resolve_rebind_import (NodeId use_dec_id, TopLevel::ImportKind &&import); + + template <typename P> + std::vector<std::pair<Rib::Definition, Namespace>> + resolve_path_in_all_ns (const P &path) + { + std::vector<std::pair<Rib::Definition, Namespace>> resolved; + + // Pair a definition with the namespace it was found in + auto pair_with_ns = [&] (Namespace ns) { + return [&, ns] (Rib::Definition def) { + auto pair = std::make_pair (def, ns); + return resolved.emplace_back (std::move (pair)); + }; + }; + + std::vector<Error> value_errors; + std::vector<Error> type_errors; + std::vector<Error> macro_errors; + + ctx.resolve_path (path, value_errors, Namespace::Values) + .map (pair_with_ns (Namespace::Values)); + ctx.resolve_path (path, type_errors, Namespace::Types) + .map (pair_with_ns (Namespace::Types)); + ctx.resolve_path (path, macro_errors, Namespace::Macros) + .map (pair_with_ns (Namespace::Macros)); + + if (!value_errors.empty () && !type_errors.empty () + && !macro_errors.empty ()) + for (auto &ent : value_errors) + collect_error (std::move (ent)); + + return resolved; + } + + // Handle an import, resolving it to its definition and adding it to the list + // of import mappings + void build_import_mapping ( + std::pair<NodeId, std::vector<TopLevel::ImportKind>> &&use_import); + TextualScope textual_scope; std::vector<Error> macro_resolve_errors; void collect_error (Error e) { macro_resolve_errors.push_back (e); } + + void finalize_simple_import (const Early::ImportPair &mapping); + + void finalize_glob_import (NameResolutionContext &ctx, + const Early::ImportPair &mapping); + + void finalize_rebind_import (const Early::ImportPair &mapping); }; } // namespace Resolver2_0 diff --git a/gcc/rust/resolve/rust-early-name-resolver.cc b/gcc/rust/resolve/rust-early-name-resolver.cc index ce427dd..fc9a26c 100644 --- a/gcc/rust/resolve/rust-early-name-resolver.cc +++ b/gcc/rust/resolve/rust-early-name-resolver.cc @@ -17,7 +17,7 @@ // <http://www.gnu.org/licenses/>. #include "rust-early-name-resolver.h" -#include "rust-ast-full.h" +#include "rust-pattern.h" #include "rust-name-resolver.h" #include "rust-macro-builtins.h" #include "rust-attribute-values.h" @@ -53,7 +53,7 @@ EarlyNameResolver::accumulate_escaped_macros (AST::Module &module) scoped (module.get_node_id (), [&module, &escaped_macros, this] { for (auto &item : module.get_items ()) { - if (item->get_ast_kind () == AST::Kind::MODULE) + if (item->get_item_kind () == AST::Item::Kind::Module) { auto &module = *static_cast<AST::Module *> (item.get ()); auto new_macros = accumulate_escaped_macros (module); @@ -64,7 +64,7 @@ EarlyNameResolver::accumulate_escaped_macros (AST::Module &module) continue; } - if (item->get_ast_kind () == AST::Kind::MACRO_RULES_DEFINITION) + if (item->get_item_kind () == AST::Item::Kind::MacroRulesDefinition) escaped_macros.emplace_back (item->clone_item ()); } }); @@ -113,7 +113,7 @@ EarlyNameResolver::visit (AST::Crate &crate) { auto new_macros = std::vector<std::unique_ptr<AST::Item>> (); - if (item->get_ast_kind () == AST::Kind::MODULE) + if (item->get_item_kind () == AST::Item::Kind::Module) new_macros = accumulate_escaped_macros ( *static_cast<AST::Module *> (item.get ())); @@ -156,9 +156,10 @@ EarlyNameResolver::visit (AST::ConstGenericParam &) void EarlyNameResolver::visit (AST::PathInExpression &path) { - for (auto &segment : path.get_segments ()) - if (segment.has_generic_args ()) - resolve_generic_args (segment.get_generic_args ()); + if (!path.is_lang_item ()) + for (auto &segment : path.get_segments ()) + if (segment.has_generic_args ()) + resolve_generic_args (segment.get_generic_args ()); } void @@ -300,7 +301,7 @@ EarlyNameResolver::visit (AST::Module &module) { auto new_macros = std::vector<std::unique_ptr<AST::Item>> (); - if (item->get_ast_kind () == AST::Kind::MODULE) + if (item->get_item_kind () == AST::Item::Kind::Module) new_macros = accumulate_escaped_macros ( *static_cast<AST::Module *> (item.get ())); @@ -353,6 +354,8 @@ EarlyNameResolver::visit (AST::TraitItemType &) void EarlyNameResolver::visit (AST::Trait &trait) { + // shouldn't need to visit trait.get_implicit_self () + for (auto &generic : trait.get_generic_params ()) generic->accept_vis (*this); @@ -474,7 +477,8 @@ EarlyNameResolver::visit (AST::MacroInvocation &invoc) bool found = resolver.get_macro_scope ().lookup (seg, &resolved_node); if (!found) { - rust_error_at (invoc.get_locus (), "unknown macro: [%s]", + rust_error_at (invoc.get_locus (), ErrorCode::E0433, + "could not resolve macro invocation %qs", seg.get ().c_str ()); return; } @@ -558,30 +562,6 @@ EarlyNameResolver::visit (AST::TupleStructPattern &pattern) } void -EarlyNameResolver::visit (AST::TraitBound &) -{} - -void -EarlyNameResolver::visit (AST::ImplTraitType &) -{} - -void -EarlyNameResolver::visit (AST::TraitObjectType &) -{} - -void -EarlyNameResolver::visit (AST::ParenthesisedType &) -{} - -void -EarlyNameResolver::visit (AST::ImplTraitTypeOneBound &) -{} - -void -EarlyNameResolver::visit (AST::TraitObjectTypeOneBound &) -{} - -void EarlyNameResolver::visit (AST::TupleType &) {} diff --git a/gcc/rust/resolve/rust-early-name-resolver.h b/gcc/rust/resolve/rust-early-name-resolver.h index 48562df..26fc84d 100644 --- a/gcc/rust/resolve/rust-early-name-resolver.h +++ b/gcc/rust/resolve/rust-early-name-resolver.h @@ -36,6 +36,7 @@ public: private: using AST::DefaultASTVisitor::visit; + /** * Execute a lambda within a scope. This is equivalent to calling * `enter_scope` before your code and `exit_scope` after. This ensures @@ -181,12 +182,6 @@ private: virtual void visit (AST::StructPatternFieldIdent &field); virtual void visit (AST::StructPattern &pattern); virtual void visit (AST::TupleStructPattern &pattern); - virtual void visit (AST::TraitBound &bound); - virtual void visit (AST::ImplTraitType &type); - virtual void visit (AST::TraitObjectType &type); - virtual void visit (AST::ParenthesisedType &type); - virtual void visit (AST::ImplTraitTypeOneBound &type); - virtual void visit (AST::TraitObjectTypeOneBound &type); virtual void visit (AST::TupleType &type); virtual void visit (AST::RawPointerType &type); virtual void visit (AST::ReferenceType &type); diff --git a/gcc/rust/resolve/rust-finalize-imports-2.0.cc b/gcc/rust/resolve/rust-finalize-imports-2.0.cc new file mode 100644 index 0000000..b0e8651 --- /dev/null +++ b/gcc/rust/resolve/rust-finalize-imports-2.0.cc @@ -0,0 +1,129 @@ +// Copyright (C) 2020-2024 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-finalize-imports-2.0.h" +#include "rust-default-resolver.h" +#include "rust-hir-map.h" +#include "rust-name-resolution-context.h" +#include "rust-rib.h" +#include "rust-toplevel-name-resolver-2.0.h" + +namespace Rust { +namespace Resolver2_0 { + +void +GlobbingVisitor::go (AST::Module *module) +{ + for (auto &i : module->get_items ()) + visit (i); +} + +void +GlobbingVisitor::visit (AST::Module &module) +{ + if (module.get_visibility ().is_public ()) + ctx.insert_globbed (module.get_name (), module.get_node_id (), + Namespace::Types); +} + +void +GlobbingVisitor::visit (AST::MacroRulesDefinition ¯o) +{ + if (macro.get_visibility ().is_public ()) + ctx.insert_globbed (macro.get_rule_name (), macro.get_node_id (), + Namespace::Macros); +} + +void +GlobbingVisitor::visit (AST::Function &function) +{ + if (function.get_visibility ().is_public ()) + ctx.insert_globbed (function.get_function_name (), function.get_node_id (), + Namespace::Values); +} + +void +GlobbingVisitor::visit (AST::StaticItem &static_item) +{ + if (static_item.get_visibility ().is_public ()) + ctx.insert_globbed (static_item.get_identifier (), + static_item.get_node_id (), Namespace::Values); +} + +void +GlobbingVisitor::visit (AST::StructStruct &struct_item) +{ + if (struct_item.get_visibility ().is_public ()) + { + ctx.insert_globbed (struct_item.get_identifier (), + struct_item.get_node_id (), Namespace::Types); + if (struct_item.is_unit_struct ()) + ctx.insert_globbed (struct_item.get_identifier (), + struct_item.get_node_id (), Namespace::Values); + } +} + +void +GlobbingVisitor::visit (AST::TupleStruct &tuple_struct) +{ + if (tuple_struct.get_visibility ().is_public ()) + { + ctx.insert_globbed (tuple_struct.get_identifier (), + tuple_struct.get_node_id (), Namespace::Types); + + ctx.insert_globbed (tuple_struct.get_identifier (), + tuple_struct.get_node_id (), Namespace::Values); + } +} + +void +GlobbingVisitor::visit (AST::Enum &enum_item) +{ + if (enum_item.get_visibility ().is_public ()) + ctx.insert_globbed (enum_item.get_identifier (), enum_item.get_node_id (), + Namespace::Types); +} + +void +GlobbingVisitor::visit (AST::Union &union_item) +{ + if (union_item.get_visibility ().is_public ()) + ctx.insert_globbed (union_item.get_identifier (), union_item.get_node_id (), + Namespace::Values); +} + +void +GlobbingVisitor::visit (AST::ConstantItem &const_item) +{ + if (const_item.get_visibility ().is_public ()) + ctx.insert_globbed (const_item.get_identifier (), const_item.get_node_id (), + Namespace::Values); +} + +void +GlobbingVisitor::visit (AST::ExternCrate &crate) +{} + +void +GlobbingVisitor::visit (AST::UseDeclaration &use) +{ + // Handle cycles ? +} + +} // namespace Resolver2_0 +} // namespace Rust diff --git a/gcc/rust/resolve/rust-finalize-imports-2.0.h b/gcc/rust/resolve/rust-finalize-imports-2.0.h new file mode 100644 index 0000000..d587a5e --- /dev/null +++ b/gcc/rust/resolve/rust-finalize-imports-2.0.h @@ -0,0 +1,53 @@ +// Copyright (C) 2020-2024 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-ast.h" +#include "rust-expr.h" +#include "rust-name-resolution-context.h" +#include "rust-toplevel-name-resolver-2.0.h" +#include "rust-early-name-resolver-2.0.h" + +namespace Rust { +namespace Resolver2_0 { + +class GlobbingVisitor : public AST::DefaultASTVisitor +{ + using AST::DefaultASTVisitor::visit; + +public: + GlobbingVisitor (NameResolutionContext &ctx) : ctx (ctx) {} + + void go (AST::Module *module); + void visit (AST::Module &module) override; + void visit (AST::MacroRulesDefinition ¯o) override; + void visit (AST::Function &function) override; + void visit (AST::StaticItem &static_item) override; + void visit (AST::StructStruct &struct_item) override; + void visit (AST::TupleStruct &tuple_struct) override; + void visit (AST::Enum &enum_item) override; + void visit (AST::Union &union_item) override; + void visit (AST::ConstantItem &const_item) override; + void visit (AST::ExternCrate &crate) override; + void visit (AST::UseDeclaration &use) override; + +private: + NameResolutionContext &ctx; +}; + +} // namespace Resolver2_0 +} // namespace Rust diff --git a/gcc/rust/resolve/rust-forever-stack.cc b/gcc/rust/resolve/rust-forever-stack.cc new file mode 100644 index 0000000..725ae0e --- /dev/null +++ b/gcc/rust/resolve/rust-forever-stack.cc @@ -0,0 +1,318 @@ +// Copyright (C) 2024 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 "expected.h" +#include "rust-ast.h" +#include "rust-diagnostics.h" +#include "rust-forever-stack.h" +#include "rust-rib.h" +#include "optional.h" + +namespace Rust { +namespace Resolver2_0 { + +bool +ForeverStackStore::Node::is_root () const +{ + return !parent.has_value (); +} + +bool +ForeverStackStore::Node::is_leaf () const +{ + return children.empty (); +} + +NodeId +ForeverStackStore::Node::get_id () const +{ + return id; +} + +ForeverStackStore::Node & +ForeverStackStore::Node::insert_child (NodeId id, tl::optional<Identifier> path, + Rib::Kind kind) +{ + auto res = children.insert ({Link (id, path), Node (kind, id, *this)}); + + rust_debug ("inserting link: Link(%d [%s]): existed? %s", id, + path.has_value () ? path.value ().as_string ().c_str () + : "<anon>", + !res.second ? "yes" : "no"); + + // sanity check on rib kind + // pick the value rib, since all ribs should have the same kind anyways + rust_assert (res.second || res.first->second.value_rib.kind == kind); + + // verify, if we're using an existing node, our paths don't contradict + if (!res.second && path.has_value ()) + { + auto other_path = res.first->first.path; + rust_assert (!other_path.has_value () + || other_path.value ().as_string () + == path.value ().as_string ()); + } + + return res.first->second; +} + +tl::optional<ForeverStackStore::Node &> +ForeverStackStore::Node::get_child (const Identifier &path) +{ + for (auto &ent : children) + { + if (ent.first.path.has_value () + && ent.first.path->as_string () == path.as_string ()) + return ent.second; + } + return tl::nullopt; +} + +tl::optional<const ForeverStackStore::Node &> +ForeverStackStore::Node::get_child (const Identifier &path) const +{ + for (auto &ent : children) + { + if (ent.first.path.has_value () + && ent.first.path->as_string () == path.as_string ()) + return ent.second; + } + return tl::nullopt; +} + +tl::optional<ForeverStackStore::Node &> +ForeverStackStore::Node::get_parent () +{ + return parent; +} + +tl::optional<const ForeverStackStore::Node &> +ForeverStackStore::Node::get_parent () const +{ + if (parent) + return *parent; + return tl::nullopt; +} + +tl::optional<const Identifier &> +ForeverStackStore::Node::get_parent_path () const +{ + if (parent.has_value ()) + for (auto &ent : parent->children) + if (ent.first.id == id && ent.first.path.has_value ()) + return ent.first.path.value (); + return tl::nullopt; +} + +Rib & +ForeverStackStore::Node::get_rib (Namespace ns) +{ + switch (ns) + { + case Namespace::Values: + return value_rib; + case Namespace::Types: + return type_rib; + case Namespace::Labels: + return label_rib; + case Namespace::Macros: + return macro_rib; + default: + rust_unreachable (); + } +} + +const Rib & +ForeverStackStore::Node::get_rib (Namespace ns) const +{ + switch (ns) + { + case Namespace::Values: + return value_rib; + case Namespace::Types: + return type_rib; + case Namespace::Labels: + return label_rib; + case Namespace::Macros: + return macro_rib; + default: + rust_unreachable (); + } +} + +tl::expected<NodeId, DuplicateNameError> +ForeverStackStore::Node::insert (const Identifier &name, NodeId node, + Namespace ns) +{ + // So what do we do here - if the Rib has already been pushed in an earlier + // pass, we might end up in a situation where it is okay to re-add new names. + // Do we just ignore that here? Do we keep track of if the Rib is new or not? + // should our cursor have info on the current node like "is it newly pushed"? + return get_rib (ns).insert (name.as_string (), + Rib::Definition::NonShadowable (node)); +} + +tl::expected<NodeId, DuplicateNameError> +ForeverStackStore::Node::insert_shadowable (const Identifier &name, NodeId node, + Namespace ns) +{ + return get_rib (ns).insert (name.as_string (), + Rib::Definition::Shadowable (node)); +} + +tl::expected<NodeId, DuplicateNameError> +ForeverStackStore::Node::insert_globbed (const Identifier &name, NodeId node, + Namespace ns) +{ + return get_rib (ns).insert (name.as_string (), + Rib::Definition::Globbed (node)); +} + +void +ForeverStackStore::Node::reverse_iter (std::function<KeepGoing (Node &)> lambda) +{ + for (Node *tmp = this; lambda (*tmp) == KeepGoing::Yes && !tmp->is_root (); + tmp = &tmp->parent.value ()) + ; +} + +void +ForeverStackStore::Node::reverse_iter ( + std::function<KeepGoing (const Node &)> lambda) const +{ + for (const Node *tmp = this; + lambda (*tmp) == KeepGoing::Yes && !tmp->is_root (); + tmp = &tmp->parent.value ()) + ; +} + +void +ForeverStackStore::Node::child_iter ( + std::function<KeepGoing (NodeId, tl::optional<const Identifier &>, Node &)> + lambda) +{ + for (auto &ent : children) + { + tl::optional<const Identifier &> path; + if (ent.first.path.has_value ()) + path = ent.first.path.value (); + auto keep_going = lambda (ent.first.id, path, ent.second); + if (keep_going == KeepGoing::No) + return; + } +} + +void +ForeverStackStore::Node::child_iter ( + std::function<KeepGoing (NodeId, tl::optional<const Identifier &>, + const Node &)> + lambda) const +{ + for (auto &ent : children) + { + tl::optional<const Identifier &> path; + if (ent.first.path.has_value ()) + path = ent.first.path.value (); + auto keep_going = lambda (ent.first.id, path, ent.second); + if (keep_going == KeepGoing::No) + return; + } +} + +ForeverStackStore::Node & +ForeverStackStore::Node::find_closest_module () +{ + // get kind of value_rib + // but all ribs should share the same kind anyways + if (value_rib.kind == Rib::Kind::Module || !parent.has_value ()) + return *this; + else + return parent->find_closest_module (); +} + +const ForeverStackStore::Node & +ForeverStackStore::Node::find_closest_module () const +{ + // get kind of value_rib + // but all ribs should share the same kind anyways + if (value_rib.kind != Rib::Kind::Module || !parent.has_value ()) + return *this; + else + return parent->find_closest_module (); +} + +tl::optional<ForeverStackStore::Node &> +ForeverStackStore::Node::dfs_node (NodeId to_find) +{ + if (id == to_find) + return *this; + + for (auto &child : children) + { + auto candidate = child.second.dfs_node (to_find); + + if (candidate.has_value ()) + return candidate; + } + + return tl::nullopt; +} + +tl::optional<const ForeverStackStore::Node &> +ForeverStackStore::Node::dfs_node (NodeId to_find) const +{ + if (id == to_find) + return *this; + + for (auto &child : children) + { + auto candidate = child.second.dfs_node (to_find); + + if (candidate.has_value ()) + return candidate; + } + + return tl::nullopt; +} + +ForeverStackStore::Node & +ForeverStackStore::get_root () +{ + return root; +} + +const ForeverStackStore::Node & +ForeverStackStore::get_root () const +{ + return root; +} + +tl::optional<ForeverStackStore::Node &> +ForeverStackStore::get_node (NodeId node_id) +{ + return root.dfs_node (node_id); +} + +tl::optional<const ForeverStackStore::Node &> +ForeverStackStore::get_node (NodeId node_id) const +{ + return root.dfs_node (node_id); +} + +} // namespace Resolver2_0 +} // namespace Rust diff --git a/gcc/rust/resolve/rust-forever-stack.h b/gcc/rust/resolve/rust-forever-stack.h index a9aca0f..81468e5 100644 --- a/gcc/rust/resolve/rust-forever-stack.h +++ b/gcc/rust/resolve/rust-forever-stack.h @@ -392,17 +392,173 @@ not contain any imports, macro definitions or macro invocations. You can look at this pass's documentation for more details on this resolution process. **/ + +/** + * Intended for use by ForeverStack to store Nodes + * Unlike ForeverStack, does not store a cursor reference + * Intended to make path resolution in multiple namespaces simpler + **/ +class ForeverStackStore +{ +public: + ForeverStackStore (NodeId crate_id) : root (Rib::Kind::Normal, crate_id) + { + rust_assert (root.is_root ()); + rust_assert (root.is_leaf ()); + } + +private: + /** + * A link between two Nodes in our trie data structure. This class represents + * the edges of the graph + */ + class Link + { + public: + Link (NodeId id, tl::optional<Identifier> path) : id (id), path (path) {} + + bool compare (const Link &other) const { return id < other.id; } + + NodeId id; + tl::optional<Identifier> path; + }; + + /* Link comparison class, which we use in a Node's `children` map */ + class LinkCmp + { + public: + bool operator() (const Link &lhs, const Link &rhs) const + { + return lhs.compare (rhs); + } + }; + +public: + class Node; + + struct DfsResult + { + Node &first; + std::string second; + }; + + struct ConstDfsResult + { + const Node &first; + std::string second; + }; + + /* Should we keep going upon seeing a Rib? */ + enum class KeepGoing + { + Yes, + No, + }; + + class Node + { + private: + friend class ForeverStackStore::ForeverStackStore; + + Node (Rib::Kind rib_kind, NodeId id, tl::optional<Node &> parent) + : value_rib (rib_kind), type_rib (rib_kind), label_rib (rib_kind), + macro_rib (rib_kind), id (id), parent (parent) + {} + Node (Rib::Kind rib_kind, NodeId id) : Node (rib_kind, id, tl::nullopt) {} + Node (Rib::Kind rib_kind, NodeId id, Node &parent) + : Node (rib_kind, id, tl::optional<Node &> (parent)) + {} + + public: + Node (const Node &) = default; + Node (Node &&) = default; + Node &operator= (const Node &) = delete; + Node &operator= (Node &&) = default; + + bool is_root () const; + bool is_leaf () const; + + NodeId get_id () const; + + Node &insert_child (NodeId id, tl::optional<Identifier> path, + Rib::Kind kind); + + tl::optional<Node &> get_child (const Identifier &path); + tl::optional<const Node &> get_child (const Identifier &path) const; + + tl::optional<Node &> get_parent (); + tl::optional<const Node &> get_parent () const; + + // finds the identifier, if any, used to link + // this node's parent to this node + tl::optional<const Identifier &> get_parent_path () const; + + Rib &get_rib (Namespace ns); + const Rib &get_rib (Namespace ns) const; + + tl::expected<NodeId, DuplicateNameError> insert (const Identifier &name, + NodeId node, Namespace ns); + tl::expected<NodeId, DuplicateNameError> + insert_shadowable (const Identifier &name, NodeId node, Namespace ns); + tl::expected<NodeId, DuplicateNameError> + insert_globbed (const Identifier &name, NodeId node, Namespace ns); + + void reverse_iter (std::function<KeepGoing (Node &)> lambda); + void reverse_iter (std::function<KeepGoing (const Node &)> lambda) const; + + void child_iter (std::function<KeepGoing ( + NodeId, tl::optional<const Identifier &>, Node &)> + lambda); + void child_iter (std::function<KeepGoing ( + NodeId, tl::optional<const Identifier &>, const Node &)> + lambda) const; + + Node &find_closest_module (); + const Node &find_closest_module () const; + + tl::optional<Node &> dfs_node (NodeId to_find); + tl::optional<const Node &> dfs_node (NodeId to_find) const; + + private: + // per-namespace ribs + Rib value_rib; + Rib type_rib; + Rib label_rib; + Rib macro_rib; + // all linked nodes + std::map<Link, Node, LinkCmp> children; + + NodeId id; // The node id of the Node's scope + + tl::optional<Node &> parent; // `None` only if the node is a root + }; + + Node &get_root (); + const Node &get_root () const; + + tl::optional<Node &> get_node (NodeId node_id); + tl::optional<const Node &> get_node (NodeId node_id) const; + +private: + Node root; +}; + template <Namespace N> class ForeverStack { public: ForeverStack () - // FIXME: Is that valid? Do we use the root? If yes, we should give the - // crate's node id to ForeverStack's constructor : root (Node (Rib (Rib::Kind::Normal), UNKNOWN_NODEID)), + lang_prelude (Node (Rib (Rib::Kind::Prelude), UNKNOWN_NODEID, root)), + extern_prelude (Node (Rib (Rib::Kind::Prelude), UNKNOWN_NODEID)), cursor_reference (root) { rust_assert (root.is_root ()); rust_assert (root.is_leaf ()); + + // TODO: Should we be using the forever stack root as the crate scope? + // TODO: Is this how we should be getting the crate node id? + auto &mappings = Analysis::Mappings::get (); + root.id = *mappings.crate_num_to_nodeid (mappings.get_current_crate ()); } /** @@ -416,7 +572,7 @@ public: * @param path An optional path if the Rib was created due to a "named" * lexical scope, like a module's. */ - void push (Rib rib, NodeId id, tl::optional<Identifier> path = {}); + void push (Rib::Kind rib_kind, NodeId id, tl::optional<Identifier> path = {}); /** * Pop the innermost Rib from the stack @@ -437,6 +593,9 @@ public: */ tl::expected<NodeId, DuplicateNameError> insert (Identifier name, NodeId id); + tl::expected<NodeId, DuplicateNameError> insert_variant (Identifier name, + NodeId id); + /** * Insert a new shadowable definition in the innermost `Rib` in this stack * @@ -453,6 +612,22 @@ public: NodeId id); /** + * Insert a new glob-originated definition in the innermost `Rib` in this + * stack + * + * @param name The name of the definition + * @param id Its NodeId + * + * @return `DuplicateNameError` if that node was already present in the Rib, + * the node's `NodeId` otherwise. + * + * @aborts if there are no `Rib`s inserted in the current map, this function + * aborts the program. + */ + tl::expected<NodeId, DuplicateNameError> insert_globbed (Identifier name, + NodeId id); + + /** * Insert a new definition at the root of this stack * * @param name The name of the definition @@ -484,6 +659,8 @@ public: * the current map, an empty one otherwise. */ tl::optional<Rib::Definition> get (const Identifier &name); + tl::optional<Rib::Definition> get_lang_prelude (const Identifier &name); + tl::optional<Rib::Definition> get_lang_prelude (const std::string &name); /** * Resolve a path to its definition in the current `ForeverStack` @@ -494,15 +671,25 @@ public: * current map, an empty one otherwise. */ template <typename S> - tl::optional<Rib::Definition> resolve_path (const std::vector<S> &segments); + tl::optional<Rib::Definition> resolve_path ( + const std::vector<S> &segments, bool has_opening_scope_resolution, + std::function<void (const S &, NodeId)> insert_segment_resolution, + std::vector<Error> &collect_errors); // FIXME: Documentation - tl::optional<Resolver::CanonicalPath> to_canonical_path (NodeId id); + tl::optional<Resolver::CanonicalPath> to_canonical_path (NodeId id) const; // FIXME: Documentation tl::optional<Rib &> to_rib (NodeId rib_id); + tl::optional<const Rib &> to_rib (NodeId rib_id) const; - std::string as_debug_string (); + std::string as_debug_string () const; + + /** + * Used to check if a module is a descendant of another module + * Intended for use in the privacy checker + */ + bool is_module_descendant (NodeId parent, NodeId child) const; private: /** @@ -539,6 +726,7 @@ private: {} bool is_root () const; + bool is_prelude () const; bool is_leaf () const; void insert_child (Link link, Node child); @@ -563,21 +751,36 @@ private: /* Reverse iterate on `Node`s from the cursor, in an outwards fashion */ void reverse_iter (std::function<KeepGoing (Node &)> lambda); + void reverse_iter (std::function<KeepGoing (const Node &)> lambda) const; /* Reverse iterate on `Node`s from a specified one, in an outwards fashion */ void reverse_iter (Node &start, std::function<KeepGoing (Node &)> lambda); + void reverse_iter (const Node &start, + std::function<KeepGoing (const Node &)> lambda) const; Node &cursor (); const Node &cursor () const; void update_cursor (Node &new_cursor); + /* The forever stack's actual nodes */ Node root; + /* + * A special prelude node used currently for resolving language builtins + * It has the root node as a parent, and acts as a "special case" for name + * resolution + */ + Node lang_prelude; + /* + * The extern prelude, used for resolving external crates + */ + Node extern_prelude; + std::reference_wrapper<Node> cursor_reference; void stream_rib (std::stringstream &stream, const Rib &rib, - const std::string &next, const std::string &next_next); + const std::string &next, const std::string &next_next) const; void stream_node (std::stringstream &stream, unsigned indentation, - const Node &node); + const Node &node) const; /* Helper types and functions for `resolve_path` */ @@ -587,13 +790,22 @@ private: Node &find_closest_module (Node &starting_point); template <typename S> - tl::optional<SegIterator<S>> - find_starting_point (const std::vector<S> &segments, Node &starting_point); + tl::optional<SegIterator<S>> find_starting_point ( + const std::vector<S> &segments, + std::reference_wrapper<Node> &starting_point, + std::function<void (const S &, NodeId)> insert_segment_resolution, + std::vector<Error> &collect_errors); template <typename S> - tl::optional<Node &> resolve_segments (Node &starting_point, - const std::vector<S> &segments, - SegIterator<S> iterator); + tl::optional<Node &> resolve_segments ( + Node &starting_point, const std::vector<S> &segments, + SegIterator<S> iterator, + std::function<void (const S &, NodeId)> insert_segment_resolution, + std::vector<Error> &collect_errors); + + tl::optional<Rib::Definition> resolve_final_segment (Node &final_node, + std::string &seg_name, + bool is_lower_self); /* Helper functions for forward resolution (to_canonical_path, to_rib...) */ struct DfsResult @@ -601,11 +813,39 @@ private: Node &first; std::string second; }; + struct ConstDfsResult + { + const Node &first; + std::string second; + }; // FIXME: Documentation tl::optional<DfsResult> dfs (Node &starting_point, NodeId to_find); + tl::optional<ConstDfsResult> dfs (const Node &starting_point, + NodeId to_find) const; // FIXME: Documentation tl::optional<Rib &> dfs_rib (Node &starting_point, NodeId to_find); + tl::optional<const Rib &> dfs_rib (const Node &starting_point, + NodeId to_find) const; + // FIXME: Documentation + tl::optional<Node &> dfs_node (Node &starting_point, NodeId to_find); + tl::optional<const Node &> dfs_node (const Node &starting_point, + NodeId to_find) const; + +public: + bool forward_declared (NodeId definition, NodeId usage) + { + if (peek ().kind != Rib::Kind::ForwardTypeParamBan) + return false; + + const auto &definition_rib = dfs_rib (cursor (), definition); + + if (!definition_rib) + return false; + + return (definition_rib + && definition_rib.value ().kind == Rib::Kind::ForwardTypeParamBan); + } }; } // namespace Resolver2_0 diff --git a/gcc/rust/resolve/rust-forever-stack.hxx b/gcc/rust/resolve/rust-forever-stack.hxx index a7d46ce..069111e 100644 --- a/gcc/rust/resolve/rust-forever-stack.hxx +++ b/gcc/rust/resolve/rust-forever-stack.hxx @@ -20,7 +20,9 @@ #include "rust-ast.h" #include "rust-diagnostics.h" #include "rust-forever-stack.h" +#include "rust-edition.h" #include "rust-rib.h" +#include "rust-unwrap-segment.h" #include "optional.h" namespace Rust { @@ -35,6 +37,13 @@ ForeverStack<N>::Node::is_root () const template <Namespace N> bool +ForeverStack<N>::Node::is_prelude () const +{ + return rib.kind == Rib::Kind::Prelude; +} + +template <Namespace N> +bool ForeverStack<N>::Node::is_leaf () const { return children.empty (); @@ -52,15 +61,26 @@ ForeverStack<N>::Node::insert_child (Link link, Node child) template <Namespace N> void -ForeverStack<N>::push (Rib rib, NodeId id, tl::optional<Identifier> path) +ForeverStack<N>::push (Rib::Kind rib_kind, NodeId id, + tl::optional<Identifier> path) { - push_inner (rib, Link (id, path)); + push_inner (rib_kind, Link (id, path)); } template <Namespace N> void ForeverStack<N>::push_inner (Rib rib, Link link) { + if (rib.kind == Rib::Kind::Prelude) + { + // If you push_inner into the prelude from outside the root, you will pop + // back into the root, which could screw up a traversal. + rust_assert (&cursor_reference.get () == &root); + // Prelude doesn't have an access path + rust_assert (!link.path); + update_cursor (this->lang_prelude); + return; + } // If the link does not exist, we create it and emplace a new `Node` with the // current node as its parent. `unordered_map::emplace` returns a pair with // the iterator and a boolean. If the value already exists, the iterator @@ -133,6 +153,16 @@ ForeverStack<N>::insert_shadowable (Identifier name, NodeId node) template <Namespace N> tl::expected<NodeId, DuplicateNameError> +ForeverStack<N>::insert_globbed (Identifier name, NodeId node) +{ + auto &innermost_rib = peek (); + + return insert_inner (innermost_rib, name.as_string (), + Rib::Definition::Globbed (node)); +} + +template <Namespace N> +tl::expected<NodeId, DuplicateNameError> ForeverStack<N>::insert_at_root (Identifier name, NodeId node) { auto &root_rib = root.rib; @@ -161,6 +191,14 @@ ForeverStack<Namespace::Labels>::insert (Identifier name, NodeId node) Rib::Definition::Shadowable (node)); } +template <> +inline tl::expected<NodeId, DuplicateNameError> +ForeverStack<Namespace::Types>::insert_variant (Identifier name, NodeId node) +{ + return insert_inner (peek (), name.as_string (), + Rib::Definition::NonShadowable (node, true)); +} + template <Namespace N> Rib & ForeverStack<N>::peek () @@ -184,6 +222,14 @@ ForeverStack<N>::reverse_iter (std::function<KeepGoing (Node &)> lambda) template <Namespace N> void +ForeverStack<N>::reverse_iter ( + std::function<KeepGoing (const Node &)> lambda) const +{ + return reverse_iter (cursor (), lambda); +} + +template <Namespace N> +void ForeverStack<N>::reverse_iter (Node &start, std::function<KeepGoing (Node &)> lambda) { @@ -203,6 +249,26 @@ ForeverStack<N>::reverse_iter (Node &start, } template <Namespace N> +void +ForeverStack<N>::reverse_iter ( + const Node &start, std::function<KeepGoing (const Node &)> lambda) const +{ + auto *tmp = &start; + + while (true) + { + auto keep_going = lambda (*tmp); + if (keep_going == KeepGoing::No) + return; + + if (tmp->is_root ()) + return; + + tmp = &tmp->parent.value (); + } +} + +template <Namespace N> typename ForeverStack<N>::Node & ForeverStack<N>::cursor () { @@ -235,10 +301,12 @@ ForeverStack<N>::get (const Identifier &name) return candidate.map_or ( [&resolved_definition] (Rib::Definition found) { - // for most namespaces, we do not need to care about various ribs - they - // are available from all contexts if defined in the current scope, or - // an outermore one. so if we do have a candidate, we can return it - // directly and stop iterating + if (found.is_variant ()) + return KeepGoing::Yes; + // for most namespaces, we do not need to care about various ribs - + // they are available from all contexts if defined in the current + // scope, or an outermore one. so if we do have a candidate, we can + // return it directly and stop iterating resolved_definition = found; return KeepGoing::No; @@ -250,6 +318,20 @@ ForeverStack<N>::get (const Identifier &name) return resolved_definition; } +template <Namespace N> +tl::optional<Rib::Definition> +ForeverStack<N>::get_lang_prelude (const Identifier &name) +{ + return lang_prelude.rib.get (name.as_string ()); +} + +template <Namespace N> +tl::optional<Rib::Definition> +ForeverStack<N>::get_lang_prelude (const std::string &name) +{ + return lang_prelude.rib.get (name); +} + template <> tl::optional<Rib::Definition> inline ForeverStack<Namespace::Labels>::get ( const Identifier &name) @@ -316,12 +398,13 @@ ForeverStack<N>::find_closest_module (Node &starting_point) * segments */ template <typename S> static inline bool -check_leading_kw_at_start (const S &segment, bool condition) +check_leading_kw_at_start (std::vector<Error> &collect_errors, const S &segment, + bool condition) { if (condition) - rust_error_at ( + collect_errors.emplace_back ( segment.get_locus (), ErrorCode::E0433, - "leading path segment %qs can only be used at the beginning of a path", + "%qs in paths can only be used in start position", segment.as_string ().c_str ()); return condition; @@ -335,52 +418,61 @@ check_leading_kw_at_start (const S &segment, bool condition) template <Namespace N> template <typename S> tl::optional<typename std::vector<S>::const_iterator> -ForeverStack<N>::find_starting_point (const std::vector<S> &segments, - Node &starting_point) +ForeverStack<N>::find_starting_point ( + const std::vector<S> &segments, std::reference_wrapper<Node> &starting_point, + std::function<void (const S &, NodeId)> insert_segment_resolution, + std::vector<Error> &collect_errors) { auto iterator = segments.begin (); - // If we need to do path segment resolution, then we start - // at the closest module. In order to resolve something like `foo::bar!()`, we - // need to get back to the surrounding module, and look for a child module - // named `foo`. - if (segments.size () > 1) - starting_point = find_closest_module (starting_point); - for (; !is_last (iterator, segments); iterator++) { - auto &seg = *iterator; - auto is_self_or_crate + auto &outer_seg = *iterator; + + if (unwrap_segment_get_lang_item (outer_seg).has_value ()) + break; + + auto &seg = unwrap_type_segment (outer_seg); + bool is_self_or_crate = seg.is_crate_path_seg () || seg.is_lower_self_seg (); // if we're after the first path segment and meet `self` or `crate`, it's // an error - we should only be seeing `super` keywords at this point - if (check_leading_kw_at_start (seg, !is_start (iterator, segments) - && is_self_or_crate)) + if (check_leading_kw_at_start (collect_errors, seg, + !is_start (iterator, segments) + && is_self_or_crate)) return tl::nullopt; if (seg.is_crate_path_seg ()) { starting_point = root; + insert_segment_resolution (outer_seg, starting_point.get ().id); iterator++; break; } if (seg.is_lower_self_seg ()) { - // do nothing and exit + // insert segment resolution and exit + starting_point = find_closest_module (starting_point); + insert_segment_resolution (outer_seg, starting_point.get ().id); iterator++; break; } if (seg.is_super_path_seg ()) { - if (starting_point.is_root ()) + starting_point = find_closest_module (starting_point); + if (starting_point.get ().is_root ()) { - rust_error_at (seg.get_locus (), ErrorCode::E0433, - "too many leading %<super%> keywords"); + collect_errors.emplace_back ( + seg.get_locus (), ErrorCode::E0433, + "too many leading %<super%> keywords"); return tl::nullopt; } - starting_point = find_closest_module (starting_point.parent.value ()); + starting_point + = find_closest_module (starting_point.get ().parent.value ()); + + insert_segment_resolution (outer_seg, starting_point.get ().id); continue; } @@ -398,73 +490,223 @@ template <typename S> tl::optional<typename ForeverStack<N>::Node &> ForeverStack<N>::resolve_segments ( Node &starting_point, const std::vector<S> &segments, - typename std::vector<S>::const_iterator iterator) + typename std::vector<S>::const_iterator iterator, + std::function<void (const S &, NodeId)> insert_segment_resolution, + std::vector<Error> &collect_errors) { - auto *current_node = &starting_point; + Node *current_node = &starting_point; for (; !is_last (iterator, segments); iterator++) { - auto &seg = *iterator; - auto str = seg.as_string (); + auto &outer_seg = *iterator; + + if (auto lang_item = unwrap_segment_get_lang_item (outer_seg)) + { + NodeId seg_id = Analysis::Mappings::get ().get_lang_item_node ( + lang_item.value ()); + current_node = &dfs_node (root, seg_id).value (); + + insert_segment_resolution (outer_seg, seg_id); + continue; + } + + auto &seg = unwrap_type_segment (outer_seg); + std::string str = seg.as_string (); rust_debug ("[ARTHUR]: resolving segment part: %s", str.c_str ()); // check that we don't encounter *any* leading keywords afterwards - if (check_leading_kw_at_start (seg, seg.is_crate_path_seg () - || seg.is_super_path_seg () - || seg.is_lower_self_seg ())) + if (check_leading_kw_at_start (collect_errors, seg, + seg.is_crate_path_seg () + || seg.is_super_path_seg () + || seg.is_lower_self_seg ())) return tl::nullopt; tl::optional<typename ForeverStack<N>::Node &> child = tl::nullopt; - for (auto &kv : current_node->children) + /* + * On every iteration this loop either + * + * 1. terminates + * + * 2. decreases the depth of the node pointed to by current_node until + * current_node reaches the root + * + * 3. If the root node is reached, and we were not able to resolve the + * segment, we search the prelude rib for the segment, by setting + * current_node to point to the prelude, and toggling the + * searched_prelude boolean to true. If current_node is the prelude + * rib, and searched_prelude is true, we will exit. + * + * This ensures termination. + * + */ + bool searched_prelude = false; + while (true) { - auto &link = kv.first; + // may set the value of child + for (auto &kv : current_node->children) + { + auto &link = kv.first; + + if (link.path.map_or ( + [&str] (Identifier path) { + auto &path_str = path.as_string (); + return str == path_str; + }, + false)) + { + child = kv.second; + break; + } + } - if (link.path.map_or ( - [&str] (Identifier path) { - auto &path_str = path.as_string (); - return str == path_str; - }, - false)) + if (child.has_value ()) { - child = kv.second; break; } - } - if (!child.has_value ()) - { - rust_error_at (seg.get_locus (), ErrorCode::E0433, - "failed to resolve path segment %qs", str.c_str ()); - return tl::nullopt; + if (N == Namespace::Types) + { + auto rib_lookup = current_node->rib.get (seg.as_string ()); + if (rib_lookup && !rib_lookup->is_ambiguous ()) + { + insert_segment_resolution (outer_seg, + rib_lookup->get_node_id ()); + return tl::nullopt; + } + } + + if (current_node->is_root () && !searched_prelude) + { + searched_prelude = true; + current_node = &lang_prelude; + continue; + } + + if (!is_start (iterator, segments) + || current_node->rib.kind == Rib::Kind::Module + || current_node->is_prelude ()) + { + return tl::nullopt; + } + + current_node = ¤t_node->parent.value (); } + // if child didn't contain a value + // the while loop above should have return'd or kept looping current_node = &child.value (); + insert_segment_resolution (outer_seg, current_node->id); } return *current_node; } +template <> +inline tl::optional<Rib::Definition> +ForeverStack<Namespace::Types>::resolve_final_segment (Node &final_node, + std::string &seg_name, + bool is_lower_self) +{ + if (is_lower_self) + return Rib::Definition::NonShadowable (final_node.id); + else + return final_node.rib.get (seg_name); +} + +template <Namespace N> +tl::optional<Rib::Definition> +ForeverStack<N>::resolve_final_segment (Node &final_node, std::string &seg_name, + bool is_lower_self) +{ + return final_node.rib.get (seg_name); +} + template <Namespace N> template <typename S> tl::optional<Rib::Definition> -ForeverStack<N>::resolve_path (const std::vector<S> &segments) +ForeverStack<N>::resolve_path ( + const std::vector<S> &segments, bool has_opening_scope_resolution, + std::function<void (const S &, NodeId)> insert_segment_resolution, + std::vector<Error> &collect_errors) { // TODO: What to do if segments.empty() ? + // handle paths with opening scopes + std::function<void (void)> cleanup_current = [] () {}; + if (has_opening_scope_resolution) + { + Node *last_current = &cursor_reference.get (); + if (get_rust_edition () == Edition::E2015) + cursor_reference = root; + else + cursor_reference = extern_prelude; + cleanup_current + = [this, last_current] () { cursor_reference = *last_current; }; + } + // if there's only one segment, we just use `get` if (segments.size () == 1) - return get (segments.back ().as_string ()); + { + auto &seg = segments.front (); + if (auto lang_item = unwrap_segment_get_lang_item (seg)) + { + NodeId seg_id = Analysis::Mappings::get ().get_lang_item_node ( + lang_item.value ()); - auto starting_point = cursor (); + insert_segment_resolution (seg, seg_id); + cleanup_current (); + // TODO: does NonShadowable matter? + return Rib::Definition::NonShadowable (seg_id); + } - return find_starting_point (segments, starting_point) - .and_then ([this, &segments, &starting_point] ( - typename std::vector<S>::const_iterator iterator) { - return resolve_segments (starting_point, segments, iterator); - }) - .and_then ([&segments] (Node final_node) { - return final_node.rib.get (segments.back ().as_string ()); - }); + tl::optional<Rib::Definition> res + = get (unwrap_type_segment (segments.back ()).as_string ()); + + if (!res) + res = get_lang_prelude ( + unwrap_type_segment (segments.back ()).as_string ()); + + if (res && !res->is_ambiguous ()) + insert_segment_resolution (segments.back (), res->get_node_id ()); + cleanup_current (); + return res; + } + + std::reference_wrapper<Node> starting_point = cursor (); + + auto res + = find_starting_point (segments, starting_point, insert_segment_resolution, + collect_errors) + .and_then ( + [this, &segments, &starting_point, &insert_segment_resolution, + &collect_errors] (typename std::vector<S>::const_iterator iterator) { + return resolve_segments (starting_point.get (), segments, iterator, + insert_segment_resolution, collect_errors); + }) + .and_then ([this, &segments, &insert_segment_resolution] ( + Node &final_node) -> tl::optional<Rib::Definition> { + // leave resolution within impl blocks to type checker + if (final_node.rib.kind == Rib::Kind::TraitOrImpl) + return tl::nullopt; + + auto &seg = unwrap_type_segment (segments.back ()); + std::string seg_name = seg.as_string (); + + // assuming this can't be a lang item segment + tl::optional<Rib::Definition> res + = resolve_final_segment (final_node, seg_name, + seg.is_lower_self_seg ()); + // Ok we didn't find it in the rib, Lets try the prelude... + if (!res) + res = get_lang_prelude (seg_name); + + if (res && !res->is_ambiguous ()) + insert_segment_resolution (segments.back (), res->get_node_id ()); + + return res; + }); + cleanup_current (); + return res; } template <Namespace N> @@ -474,9 +716,48 @@ ForeverStack<N>::dfs (ForeverStack<N>::Node &starting_point, NodeId to_find) auto values = starting_point.rib.get_values (); for (auto &kv : values) - for (auto id : kv.second.ids) - if (id == to_find) - return {{starting_point, kv.first}}; + { + for (auto id : kv.second.ids_shadowable) + if (id == to_find) + return {{starting_point, kv.first}}; + for (auto id : kv.second.ids_non_shadowable) + if (id == to_find) + return {{starting_point, kv.first}}; + for (auto id : kv.second.ids_globbed) + if (id == to_find) + return {{starting_point, kv.first}}; + } + + for (auto &child : starting_point.children) + { + auto candidate = dfs (child.second, to_find); + + if (candidate.has_value ()) + return candidate; + } + + return tl::nullopt; +} + +template <Namespace N> +tl::optional<typename ForeverStack<N>::ConstDfsResult> +ForeverStack<N>::dfs (const ForeverStack<N>::Node &starting_point, + NodeId to_find) const +{ + auto values = starting_point.rib.get_values (); + + for (auto &kv : values) + { + for (auto id : kv.second.ids_shadowable) + if (id == to_find) + return {{starting_point, kv.first}}; + for (auto id : kv.second.ids_non_shadowable) + if (id == to_find) + return {{starting_point, kv.first}}; + for (auto id : kv.second.ids_globbed) + if (id == to_find) + return {{starting_point, kv.first}}; + } for (auto &child : starting_point.children) { @@ -491,20 +772,20 @@ ForeverStack<N>::dfs (ForeverStack<N>::Node &starting_point, NodeId to_find) template <Namespace N> tl::optional<Resolver::CanonicalPath> -ForeverStack<N>::to_canonical_path (NodeId id) +ForeverStack<N>::to_canonical_path (NodeId id) const { // find the id in the current forever stack, starting from the root, // performing either a BFS or DFS once the Node containing the ID is found, go // back up to the root (parent().parent().parent()...) accumulate link // segments reverse them that's your canonical path - return dfs (root, id).map ([this, id] (DfsResult tuple) { + return dfs (root, id).map ([this, id] (ConstDfsResult tuple) { auto containing_node = tuple.first; auto name = tuple.second; auto segments = std::vector<Resolver::CanonicalPath> (); - reverse_iter (containing_node, [&segments] (Node ¤t) { + reverse_iter (containing_node, [&segments] (const Node ¤t) { if (current.is_root ()) return KeepGoing::No; @@ -516,7 +797,7 @@ ForeverStack<N>::to_canonical_path (NodeId id) auto &link = kv.first; auto &child = kv.second; - if (link.id == child.id) + if (current.id == child.id) { outer_link = &link; break; @@ -534,7 +815,12 @@ ForeverStack<N>::to_canonical_path (NodeId id) return KeepGoing::Yes; }); - auto path = Resolver::CanonicalPath::create_empty (); + auto &mappings = Analysis::Mappings::get (); + CrateNum crate_num = mappings.lookup_crate_num (root.id).value (); + auto path = Resolver::CanonicalPath::new_seg ( + root.id, mappings.get_crate_name (crate_num).value ()); + path.set_crate_num (crate_num); + for (const auto &segment : segments) path = path.append (segment); @@ -549,12 +835,50 @@ template <Namespace N> tl::optional<Rib &> ForeverStack<N>::dfs_rib (ForeverStack<N>::Node &starting_point, NodeId to_find) { + return dfs_node (starting_point, to_find).map ([] (Node &x) -> Rib & { + return x.rib; + }); +} + +template <Namespace N> +tl::optional<const Rib &> +ForeverStack<N>::dfs_rib (const ForeverStack<N>::Node &starting_point, + NodeId to_find) const +{ + return dfs_node (starting_point, to_find) + .map ([] (const Node &x) -> const Rib & { return x.rib; }); +} + +template <Namespace N> +tl::optional<typename ForeverStack<N>::Node &> +ForeverStack<N>::dfs_node (ForeverStack<N>::Node &starting_point, + NodeId to_find) +{ + if (starting_point.id == to_find) + return starting_point; + + for (auto &child : starting_point.children) + { + auto candidate = dfs_node (child.second, to_find); + + if (candidate.has_value ()) + return candidate; + } + + return tl::nullopt; +} + +template <Namespace N> +tl::optional<const typename ForeverStack<N>::Node &> +ForeverStack<N>::dfs_node (const ForeverStack<N>::Node &starting_point, + NodeId to_find) const +{ if (starting_point.id == to_find) - return starting_point.rib; + return starting_point; for (auto &child : starting_point.children) { - auto candidate = dfs_rib (child.second, to_find); + auto candidate = dfs_node (child.second, to_find); if (candidate.has_value ()) return candidate; @@ -571,18 +895,29 @@ ForeverStack<N>::to_rib (NodeId rib_id) } template <Namespace N> +tl::optional<const Rib &> +ForeverStack<N>::to_rib (NodeId rib_id) const +{ + return dfs_rib (root, rib_id); +} + +template <Namespace N> void ForeverStack<N>::stream_rib (std::stringstream &stream, const Rib &rib, const std::string &next, - const std::string &next_next) + const std::string &next_next) const { + std::string rib_kind = Rib::kind_to_string (rib.kind); + stream << next << "rib [" << rib_kind << "]: {"; if (rib.get_values ().empty ()) { - stream << next << "rib: {},\n"; + stream << "}\n"; return; } - - stream << next << "rib: {\n"; + else + { + stream << "\n"; + } for (const auto &kv : rib.get_values ()) stream << next_next << kv.first << ": " << kv.second.to_string () << "\n"; @@ -593,7 +928,7 @@ ForeverStack<N>::stream_rib (std::stringstream &stream, const Rib &rib, template <Namespace N> void ForeverStack<N>::stream_node (std::stringstream &stream, unsigned indentation, - const ForeverStack<N>::Node &node) + const ForeverStack<N>::Node &node) const { auto indent = std::string (indentation, ' '); auto next = std::string (indentation + 4, ' '); @@ -625,7 +960,7 @@ ForeverStack<N>::stream_node (std::stringstream &stream, unsigned indentation, template <Namespace N> std::string -ForeverStack<N>::as_debug_string () +ForeverStack<N>::as_debug_string () const { std::stringstream stream; @@ -634,6 +969,13 @@ ForeverStack<N>::as_debug_string () return stream.str (); } +template <Namespace N> +bool +ForeverStack<N>::is_module_descendant (NodeId parent, NodeId child) const +{ + return dfs_node (dfs_node (root, parent).value (), child).has_value (); +} + // FIXME: Can we add selftests? } // namespace Resolver2_0 diff --git a/gcc/rust/resolve/rust-ice-finalizer.cc b/gcc/rust/resolve/rust-ice-finalizer.cc new file mode 100644 index 0000000..bd4763f --- /dev/null +++ b/gcc/rust/resolve/rust-ice-finalizer.cc @@ -0,0 +1,36 @@ +// Copyright (C) 2020-2024 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-ice-finalizer.h" + +namespace Rust { +namespace Resolver { + +void ATTRIBUTE_NORETURN +funny_ice_text_finalizer (diagnostic_text_output_format &text_output, + const diagnostic_info *diagnostic, + diagnostic_t diag_kind) +{ + gcc_assert (diag_kind == DK_ICE_NOBT); + default_diagnostic_text_finalizer (text_output, diagnostic, diag_kind); + fnotice (stderr, "You have broken GCC Rust. This is a feature.\n"); + exit (ICE_EXIT_CODE); +} + +} // namespace Resolver +} // namespace Rust diff --git a/gcc/rust/resolve/rust-ice-finalizer.h b/gcc/rust/resolve/rust-ice-finalizer.h new file mode 100644 index 0000000..85ab88f --- /dev/null +++ b/gcc/rust/resolve/rust-ice-finalizer.h @@ -0,0 +1,65 @@ +// Copyright (C) 2020-2024 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_ICE_FINALIZER_H +#define RUST_ICE_FINALIZER_H + +#include "rust-linemap.h" +#include "diagnostic.h" + +namespace Rust { +namespace Resolver { + +/* The "break rust" Easter egg. + + Backstory: once upon a time, there used to be a bug in rustc: it would ICE + during typechecking on a 'break' with an expression outside of a loop. The + issue has been reported [0] and fixed [1], but in recognition of this, as a + special Easter egg, "break rust" was made to intentionally cause an ICE. + + [0]: https://github.com/rust-lang/rust/issues/43162 + [1]: https://github.com/rust-lang/rust/pull/43745 + + This was made in a way that does not break valid programs: namely, it only + happens when the 'break' is outside of a loop (so invalid anyway). + + GCC Rust supports this essential feature as well, but in a slightly + different way. Instead of delaying the error until type checking, we emit + it here in the resolution phase. We, too, only do this to programs that + are already invalid: we only emit our funny ICE if the name "rust" (which + must be immediately inside a break-with-a-value expression) fails to + resolve. Note that "break (rust)" does not trigger our ICE, only using + "break rust" directly does, and only if there's no "rust" in scope. We do + this in the same way regardless of whether the "break" is outside of a loop + or inside one. + + As a GNU extension, we also support "break gcc", much to the same effect, + subject to the same rules. */ + +/* The finalizer for our funny ICE. This prints a custom message instead of + the default bug reporting instructions, as there is no bug to report. */ + +void ATTRIBUTE_NORETURN +funny_ice_text_finalizer (diagnostic_text_output_format &text_output, + const diagnostic_info *diagnostic, + diagnostic_t diag_kind); + +} // namespace Resolver +} // namespace Rust + +#endif /* ! RUST_ICE_FINALIZER_H */ diff --git a/gcc/rust/resolve/rust-late-name-resolver-2.0.cc b/gcc/rust/resolve/rust-late-name-resolver-2.0.cc index 9ac0945..6ec0422 100644 --- a/gcc/rust/resolve/rust-late-name-resolver-2.0.cc +++ b/gcc/rust/resolve/rust-late-name-resolver-2.0.cc @@ -18,13 +18,17 @@ #include "optional.h" #include "rust-ast-full.h" +#include "rust-diagnostics.h" #include "rust-hir-map.h" #include "rust-late-name-resolver-2.0.h" #include "rust-default-resolver.h" #include "rust-name-resolution-context.h" #include "rust-path.h" +#include "rust-system.h" #include "rust-tyty.h" #include "rust-hir-type-check.h" +#include "rust-ice-finalizer.h" +#include "rust-ast.h" namespace Rust { namespace Resolver2_0 { @@ -87,19 +91,21 @@ Late::setup_builtin_types () // insert it in the type context... }; - for (const auto &builtin : builtins) - { - // we should be able to use `insert_at_root` or `insert` here, since we're - // at the root :) hopefully! - auto ok = ctx.types.insert (builtin.name, builtin.node_id); - rust_assert (ok); + // There's a special Rib for putting prelude items, since prelude items need + // to satisfy certain special rules. + ctx.scoped (Rib::Kind::Prelude, 0, [this, &ty_ctx] (void) -> void { + for (const auto &builtin : builtins) + { + auto ok = ctx.types.insert (builtin.name, builtin.node_id); + rust_assert (ok); - ctx.mappings.insert_node_to_hir (builtin.node_id, builtin.hir_id); - ty_ctx.insert_builtin (builtin.hir_id, builtin.node_id, builtin.type); - } + ctx.mappings.insert_node_to_hir (builtin.node_id, builtin.hir_id); + ty_ctx.insert_builtin (builtin.hir_id, builtin.node_id, builtin.type); + } + }); // ...here! - auto *unit_type = TyTy::TupleType::get_unit_type (next_hir_id ()); + auto *unit_type = TyTy::TupleType::get_unit_type (); ty_ctx.insert_builtin (unit_type->get_ref (), next_node_id (), unit_type); } @@ -123,10 +129,72 @@ Late::new_label (Identifier name, NodeId id) } void +Late::visit (AST::ForLoopExpr &expr) +{ + visit_outer_attrs (expr); + + ctx.bindings.enter (BindingSource::For); + + visit (expr.get_pattern ()); + + ctx.bindings.exit (); + + visit (expr.get_iterator_expr ()); + visit (expr.get_loop_label ()); + visit (expr.get_loop_block ()); +} + +void +Late::visit (AST::IfLetExpr &expr) +{ + visit_outer_attrs (expr); + + ctx.bindings.enter (BindingSource::Let); + + for (auto &pattern : expr.get_patterns ()) + visit (pattern); + + ctx.bindings.exit (); + + visit (expr.get_value_expr ()); + visit (expr.get_if_block ()); +} + +void +Late::visit (AST::MatchArm &arm) +{ + visit_outer_attrs (arm); + + ctx.bindings.enter (BindingSource::Match); + + for (auto &pattern : arm.get_patterns ()) + visit (pattern); + + ctx.bindings.exit (); + + if (arm.has_match_arm_guard ()) + visit (arm.get_guard_expr ()); +} + +void Late::visit (AST::LetStmt &let) { - // so we don't need that method - DefaultResolver::visit (let); + DefaultASTVisitor::visit_outer_attrs (let); + if (let.has_type ()) + visit (let.get_type ()); + // visit expression before pattern + // this makes variable shadowing work properly + if (let.has_init_expr ()) + visit (let.get_init_expr ()); + + ctx.bindings.enter (BindingSource::Let); + + visit (let.get_pattern ()); + + ctx.bindings.exit (); + + if (let.has_else_expr ()) + visit (let.get_init_expr ()); // how do we deal with the fact that `let a = blipbloup` should look for a // label and cannot go through function ribs, but `let a = blipbloup()` can? @@ -151,10 +219,144 @@ Late::visit (AST::IdentifierPattern &identifier) // do we insert in labels or in values // but values does not allow shadowing... since functions cannot shadow // do we insert functions in labels as well? - auto ok - = ctx.values.insert (identifier.get_ident (), identifier.get_node_id ()); - rust_assert (ok); + if (ctx.bindings.peek ().is_and_bound (identifier.get_ident ())) + { + if (ctx.bindings.peek ().get_source () == BindingSource::Param) + rust_error_at ( + identifier.get_locus (), ErrorCode::E0415, + "identifier %qs is bound more than once in the same parameter list", + identifier.as_string ().c_str ()); + else + rust_error_at ( + identifier.get_locus (), ErrorCode::E0416, + "identifier %qs is bound more than once in the same pattern", + identifier.as_string ().c_str ()); + return; + } + + ctx.bindings.peek ().insert_ident (identifier.get_ident ()); + + if (ctx.bindings.peek ().is_or_bound (identifier.get_ident ())) + { + // FIXME: map usage instead + std::ignore = ctx.values.insert_shadowable (identifier.get_ident (), + identifier.get_node_id ()); + } + else + { + // We do want to ignore duplicated data because some situations rely on + // it. + std::ignore = ctx.values.insert_shadowable (identifier.get_ident (), + identifier.get_node_id ()); + } +} + +void +Late::visit (AST::AltPattern &pattern) +{ + ctx.bindings.peek ().push (Binding::Kind::Or); + for (auto &alt : pattern.get_alts ()) + { + ctx.bindings.peek ().push (Binding::Kind::Product); + visit (alt); + ctx.bindings.peek ().merge (); + } + ctx.bindings.peek ().merge (); +} + +void +Late::visit_function_params (AST::Function &function) +{ + ctx.bindings.enter (BindingSource::Param); + + for (auto ¶m : function.get_function_params ()) + visit (param); + + ctx.bindings.exit (); +} + +void +Late::visit (AST::StructPatternFieldIdent &field) +{ + // We do want to ignore duplicated data because some situations rely on it. + std::ignore = ctx.values.insert_shadowable (field.get_identifier (), + field.get_node_id ()); +} + +void +Late::visit (AST::SelfParam ¶m) +{ + // handle similar to AST::IdentifierPattern + + DefaultResolver::visit (param); + // FIXME: this location should be a bit off + // ex: would point to the begining of "mut self" instead of the "self" + std::ignore = ctx.values.insert (Identifier ("self", param.get_locus ()), + param.get_node_id ()); +} + +void +Late::visit (AST::BreakExpr &expr) +{ + if (expr.has_label ()) + resolve_label (expr.get_label_unchecked ().get_lifetime ()); + + if (expr.has_break_expr ()) + { + auto &break_expr = expr.get_break_expr (); + if (break_expr.get_expr_kind () == AST::Expr::Kind::Identifier) + { + /* This is a break with an expression, and the expression is + just a single identifier. See if the identifier is either + "rust" or "gcc", in which case we have "break rust" or "break + gcc", and so may need to emit our funny error. We cannot yet + emit the error here though, because the identifier may still + be in scope, and ICE'ing on valid programs would not be very + funny. */ + std::string ident + = static_cast<AST::IdentifierExpr &> (expr.get_break_expr ()) + .as_string (); + if (ident == "rust" || ident == "gcc") + funny_error = true; + } + } + + DefaultResolver::visit (expr); + + funny_error = false; +} + +void +Late::visit (AST::LoopLabel &label) +{ + auto &lifetime = label.get_lifetime (); + ctx.labels.insert (Identifier (lifetime.as_string (), lifetime.get_locus ()), + lifetime.get_node_id ()); +} + +void +Late::resolve_label (AST::Lifetime &lifetime) +{ + if (auto resolved = ctx.labels.get (lifetime.as_string ())) + { + if (resolved->get_node_id () != lifetime.get_node_id ()) + ctx.map_usage (Usage (lifetime.get_node_id ()), + Definition (resolved->get_node_id ())); + } + else + rust_error_at (lifetime.get_locus (), ErrorCode::E0426, + "use of undeclared label %qs", + lifetime.as_string ().c_str ()); +} + +void +Late::visit (AST::ContinueExpr &expr) +{ + if (expr.has_label ()) + resolve_label (expr.get_label_unchecked ()); + + DefaultResolver::visit (expr); } void @@ -163,55 +365,115 @@ Late::visit (AST::IdentifierExpr &expr) // TODO: same thing as visit(PathInExpression) here? tl::optional<Rib::Definition> resolved = tl::nullopt; - auto label = ctx.labels.get (expr.get_ident ()); - auto value = ctx.values.get (expr.get_ident ()); - - if (label) + if (auto value = ctx.values.get (expr.get_ident ())) + { + resolved = value; + } + else if (auto type = ctx.types.get (expr.get_ident ())) { - resolved = label; + resolved = type; } - else if (value) + else if (funny_error) { - resolved = value; + diagnostic_text_finalizer (global_dc) = Resolver::funny_ice_text_finalizer; + emit_diagnostic (DK_ICE_NOBT, expr.get_locus (), -1, + "are you trying to break %s? how dare you?", + expr.as_string ().c_str ()); } else { - rust_error_at (expr.get_locus (), - "could not resolve identifier expression: %qs", - expr.get_ident ().as_string ().c_str ()); + if (auto type = ctx.types.get_lang_prelude (expr.get_ident ())) + { + resolved = type; + } + else + { + rust_error_at (expr.get_locus (), ErrorCode::E0425, + "cannot find value %qs in this scope", + expr.get_ident ().as_string ().c_str ()); + return; + } + } + + if (resolved->is_ambiguous ()) + { + rust_error_at (expr.get_locus (), ErrorCode::E0659, "%qs is ambiguous", + expr.as_string ().c_str ()); return; } ctx.map_usage (Usage (expr.get_node_id ()), Definition (resolved->get_node_id ())); - // in the old resolver, resolutions are kept in the resolver, not the mappings - // :/ how do we deal with that? - // ctx.mappings.insert_resolved_name(expr, resolved); - // For empty types, do we perform a lookup in ctx.types or should the // toplevel instead insert a name in ctx.values? (like it currently does) } void +Late::visit (AST::StructExprFieldIdentifier &expr) +{ + tl::optional<Rib::Definition> resolved = tl::nullopt; + + if (auto value = ctx.values.get (expr.get_field_name ())) + { + resolved = value; + } + // seems like we don't need a type namespace lookup + else + { + rust_error_at (expr.get_locus (), "could not resolve struct field: %qs", + expr.get_field_name ().as_string ().c_str ()); + return; + } + + if (resolved->is_ambiguous ()) + { + rust_error_at (expr.get_locus (), ErrorCode::E0659, "%qs is ambiguous", + expr.as_string ().c_str ()); + return; + } + + ctx.map_usage (Usage (expr.get_node_id ()), + Definition (resolved->get_node_id ())); +} + +void Late::visit (AST::PathInExpression &expr) { // TODO: How do we have a nice error with `can't capture dynamic environment // in a function item` error here? // do we emit it in `get<Namespace::Labels>`? - auto value = ctx.values.resolve_path (expr.get_segments ()); - if (!value.has_value ()) - rust_unreachable (); // Should have been resolved earlier + DefaultResolver::visit (expr); - if (value->is_ambiguous ()) + if (expr.is_lang_item ()) + { + ctx.map_usage (Usage (expr.get_node_id ()), + Definition (Analysis::Mappings::get ().get_lang_item_node ( + expr.get_lang_item ()))); + return; + } + + auto resolved = ctx.resolve_path (expr, Namespace::Values, Namespace::Types); + + if (!resolved) + { + if (!ctx.lookup (expr.get_segments ().front ().get_node_id ())) + rust_error_at (expr.get_locus (), ErrorCode::E0433, + "Cannot find path %qs in this scope", + expr.as_simple_path ().as_string ().c_str ()); + return; + } + + if (resolved->is_ambiguous ()) { rust_error_at (expr.get_locus (), ErrorCode::E0659, "%qs is ambiguous", expr.as_string ().c_str ()); return; } + ctx.map_usage (Usage (expr.get_node_id ()), - Definition (value->get_node_id ())); + Definition (resolved->get_node_id ())); } void @@ -222,31 +484,180 @@ Late::visit (AST::TypePath &type) // maybe we can overload `resolve_path<Namespace::Types>` to only do // typepath-like path resolution? that sounds good - auto resolved = ctx.types.get (type.get_segments ().back ()->as_string ()); + DefaultResolver::visit (type); + + // this *should* mostly work + // TODO: make sure typepath-like path resolution (?) is working + auto resolved = ctx.resolve_path (type, Namespace::Types); + + if (!resolved.has_value ()) + { + if (!ctx.lookup (type.get_segments ().front ()->get_node_id ())) + rust_error_at (type.get_locus (), "could not resolve type path %qs", + type.as_string ().c_str ()); + return; + } + + if (resolved->is_ambiguous ()) + { + rust_error_at (type.get_locus (), ErrorCode::E0659, "%qs is ambiguous", + type.as_string ().c_str ()); + return; + } + + if (ctx.types.forward_declared (resolved->get_node_id (), + type.get_node_id ())) + { + rust_error_at (type.get_locus (), ErrorCode::E0128, + "type parameters with a default cannot use forward " + "declared identifiers"); + } ctx.map_usage (Usage (type.get_node_id ()), Definition (resolved->get_node_id ())); } void +Late::visit (AST::Trait &trait) +{ + // kind of weird how this is done + // names are resolved to the node id of trait.get_implicit_self () + // which is then resolved to the node id of trait + // we set up the latter mapping here + ctx.map_usage (Usage (trait.get_implicit_self ().get_node_id ()), + Definition (trait.get_node_id ())); + + DefaultResolver::visit (trait); +} + +void +Late::visit (AST::StructStruct &s) +{ + auto s_vis = [this, &s] () { AST::DefaultASTVisitor::visit (s); }; + ctx.scoped (Rib::Kind::Item, s.get_node_id (), s_vis); +} + +void +Late::visit (AST::StructExprStruct &s) +{ + visit_outer_attrs (s); + visit_inner_attrs (s); + DefaultResolver::visit (s.get_struct_name ()); + + auto resolved = ctx.resolve_path (s.get_struct_name (), Namespace::Types); + + ctx.map_usage (Usage (s.get_struct_name ().get_node_id ()), + Definition (resolved->get_node_id ())); +} + +void Late::visit (AST::StructExprStructBase &s) { - auto resolved = ctx.types.get (s.get_struct_name ().as_string ()); + visit_outer_attrs (s); + visit_inner_attrs (s); + DefaultResolver::visit (s.get_struct_name ()); + visit (s.get_struct_base ()); + + auto resolved = ctx.resolve_path (s.get_struct_name (), Namespace::Types); ctx.map_usage (Usage (s.get_struct_name ().get_node_id ()), Definition (resolved->get_node_id ())); - DefaultResolver::visit (s); } void Late::visit (AST::StructExprStructFields &s) { - auto resolved = ctx.types.get (s.get_struct_name ().as_string ()); + visit_outer_attrs (s); + visit_inner_attrs (s); + DefaultResolver::visit (s.get_struct_name ()); + if (s.has_struct_base ()) + visit (s.get_struct_base ()); + for (auto &field : s.get_fields ()) + visit (field); + + auto resolved = ctx.resolve_path (s.get_struct_name (), Namespace::Types); ctx.map_usage (Usage (s.get_struct_name ().get_node_id ()), Definition (resolved->get_node_id ())); +} + +// needed because Late::visit (AST::GenericArg &) is non-virtual +void +Late::visit (AST::GenericArgs &args) +{ + for (auto &lifetime : args.get_lifetime_args ()) + visit (lifetime); + + for (auto &generic : args.get_generic_args ()) + visit (generic); + + for (auto &binding : args.get_binding_args ()) + visit (binding); +} + +void +Late::visit (AST::GenericArg &arg) +{ + if (arg.get_kind () == AST::GenericArg::Kind::Either) + { + // prefer type parameter to const parameter on ambiguity + auto type = ctx.types.get (arg.get_path ()); + auto value = ctx.values.get (arg.get_path ()); + + if (!type.has_value () && value.has_value ()) + arg = arg.disambiguate_to_const (); + else + arg = arg.disambiguate_to_type (); + } + + DefaultResolver::visit (arg); +} + +template <class Closure> +static void +add_captures (Closure &closure, NameResolutionContext &ctx) +{ + auto vals = ctx.values.peek ().get_values (); + for (auto &val : vals) + { + ctx.mappings.add_capture (closure.get_node_id (), + val.second.get_node_id ()); + } +} + +void +Late::visit (AST::ClosureExprInner &closure) +{ + add_captures (closure, ctx); + + visit_outer_attrs (closure); + + ctx.bindings.enter (BindingSource::Param); + + for (auto ¶m : closure.get_params ()) + visit (param); + + ctx.bindings.exit (); + + visit (closure.get_definition_expr ()); +} + +void +Late::visit (AST::ClosureExprInnerTyped &closure) +{ + add_captures (closure, ctx); + + visit_outer_attrs (closure); + + ctx.bindings.enter (BindingSource::Param); + + for (auto ¶m : closure.get_params ()) + visit (param); + + ctx.bindings.exit (); - DefaultResolver::visit (s); + visit (closure.get_return_type ()); + visit (closure.get_definition_block ()); } } // namespace Resolver2_0 diff --git a/gcc/rust/resolve/rust-late-name-resolver-2.0.h b/gcc/rust/resolve/rust-late-name-resolver-2.0.h index b44b2d9..171d9bf 100644 --- a/gcc/rust/resolve/rust-late-name-resolver-2.0.h +++ b/gcc/rust/resolve/rust-late-name-resolver-2.0.h @@ -21,6 +21,7 @@ #include "rust-ast-full.h" #include "rust-default-resolver.h" +#include "rust-expr.h" namespace Rust { namespace Resolver2_0 { @@ -36,22 +37,46 @@ public: void new_label (Identifier name, NodeId id); + // Specialized visit bits + void visit_function_params (AST::Function &function) override; + // some more label declarations void visit (AST::LetStmt &) override; // TODO: Do we need this? // void visit (AST::Method &) override; void visit (AST::IdentifierPattern &) override; + void visit (AST::StructPatternFieldIdent &) override; + void visit (AST::AltPattern &) override; + void visit (AST::SelfParam &) override; + void visit (AST::MatchArm &) override; + void visit (AST::ForLoopExpr &) override; + void visit (AST::IfLetExpr &) override; // resolutions void visit (AST::IdentifierExpr &) override; + void visit (AST::StructExprFieldIdentifier &) override; + void visit (AST::BreakExpr &) override; + void visit (AST::ContinueExpr &) override; + void visit (AST::LoopLabel &) override; void visit (AST::PathInExpression &) override; void visit (AST::TypePath &) override; + void visit (AST::Trait &) override; + void visit (AST::StructExprStruct &) override; void visit (AST::StructExprStructBase &) override; void visit (AST::StructExprStructFields &) override; + void visit (AST::StructStruct &) override; + void visit (AST::GenericArgs &) override; + void visit (AST::GenericArg &); + void visit (AST::ClosureExprInner &) override; + void visit (AST::ClosureExprInnerTyped &) override; private: + void resolve_label (AST::Lifetime &lifetime); + /* Setup Rust's builtin types (u8, i32, !...) in the resolver */ void setup_builtin_types (); + + bool funny_error; }; // TODO: Add missing mappings and data structures diff --git a/gcc/rust/resolve/rust-name-resolution-context.cc b/gcc/rust/resolve/rust-name-resolution-context.cc index d964684..f098e48 100644 --- a/gcc/rust/resolve/rust-name-resolution-context.cc +++ b/gcc/rust/resolve/rust-name-resolution-context.cc @@ -23,6 +23,65 @@ namespace Rust { namespace Resolver2_0 { +BindingLayer::BindingLayer (BindingSource source) : source (source) +{ + push (Binding::Kind::Product); +} + +bool +BindingLayer::bind_test (Identifier ident, Binding::Kind kind) +{ + for (auto &bind : bindings) + { + if (bind.set.find (ident) != bind.set.cend () && bind.kind == kind) + { + return true; + } + } + return false; +} + +void +BindingLayer::push (Binding::Kind kind) +{ + bindings.push_back (Binding (kind)); +} + +bool +BindingLayer::is_and_bound (Identifier ident) +{ + return bind_test (ident, Binding::Kind::Product); +} + +bool +BindingLayer::is_or_bound (Identifier ident) +{ + return bind_test (ident, Binding::Kind::Or); +} + +void +BindingLayer::insert_ident (Identifier ident) +{ + bindings.back ().set.insert (ident); +} + +void +BindingLayer::merge () +{ + auto last_binding = bindings.back (); + bindings.pop_back (); + for (auto &value : last_binding.set) + { + bindings.back ().set.insert (value); + } +} + +BindingSource +BindingLayer::get_source () const +{ + return source; +} + NameResolutionContext::NameResolutionContext () : mappings (Analysis::Mappings::get ()) {} @@ -46,6 +105,12 @@ NameResolutionContext::insert (Identifier name, NodeId id, Namespace ns) } tl::expected<NodeId, DuplicateNameError> +NameResolutionContext::insert_variant (Identifier name, NodeId id) +{ + return types.insert_variant (name, id); +} + +tl::expected<NodeId, DuplicateNameError> NameResolutionContext::insert_shadowable (Identifier name, NodeId id, Namespace ns) { @@ -64,6 +129,24 @@ NameResolutionContext::insert_shadowable (Identifier name, NodeId id, } } +tl::expected<NodeId, DuplicateNameError> +NameResolutionContext::insert_globbed (Identifier name, NodeId id, Namespace ns) +{ + switch (ns) + { + case Namespace::Values: + return values.insert_globbed (name, id); + case Namespace::Types: + return types.insert_globbed (name, id); + case Namespace::Macros: + return macros.insert_globbed (name, id); + case Namespace::Labels: + default: + // return labels.insert (name, id); + rust_unreachable (); + } +} + void NameResolutionContext::map_usage (Usage usage, Definition definition) { @@ -74,7 +157,7 @@ NameResolutionContext::map_usage (Usage usage, Definition definition) } tl::optional<NodeId> -NameResolutionContext::lookup (NodeId usage) +NameResolutionContext::lookup (NodeId usage) const { auto it = resolved_nodes.find (Usage (usage)); @@ -85,13 +168,14 @@ NameResolutionContext::lookup (NodeId usage) } void -NameResolutionContext::scoped (Rib rib, NodeId id, +NameResolutionContext::scoped (Rib::Kind rib_kind, NodeId id, std::function<void (void)> lambda, tl::optional<Identifier> path) { - values.push (rib, id, path); - types.push (rib, id, path); - macros.push (rib, id, path); + // NOTE: You must be at the root node when pushing the prelude rib. + values.push (rib_kind, id, path); + types.push (rib_kind, id, path); + macros.push (rib_kind, id, path); // labels.push (rib, id); lambda (); @@ -103,17 +187,21 @@ NameResolutionContext::scoped (Rib rib, NodeId id, } void -NameResolutionContext::scoped (Rib rib, Namespace ns, NodeId scope_id, +NameResolutionContext::scoped (Rib::Kind rib_kind, Namespace ns, + NodeId scope_id, std::function<void (void)> lambda, tl::optional<Identifier> path) { + // This could work... I'm not sure why you would want to do this though. + rust_assert (rib_kind != Rib::Kind::Prelude); + switch (ns) { case Namespace::Values: - values.push (rib, scope_id, path); + values.push (rib_kind, scope_id, path); break; case Namespace::Types: - types.push (rib, scope_id, path); + types.push (rib_kind, scope_id, path); break; case Namespace::Labels: case Namespace::Macros: diff --git a/gcc/rust/resolve/rust-name-resolution-context.h b/gcc/rust/resolve/rust-name-resolution-context.h index 3605392..19ba750 100644 --- a/gcc/rust/resolve/rust-name-resolution-context.h +++ b/gcc/rust/resolve/rust-name-resolution-context.h @@ -22,6 +22,8 @@ #include "optional.h" #include "rust-forever-stack.h" #include "rust-hir-map.h" +#include "rust-rib.h" +#include "rust-stacked-contexts.h" namespace Rust { namespace Resolver2_0 { @@ -155,6 +157,62 @@ public: NodeId id; }; +struct Binding +{ + enum class Kind + { + Product, + Or, + } kind; + + std::unordered_set<Identifier> set; + + Binding (Binding::Kind kind) : kind (kind) {} +}; + +/** + * Used to identify the source of a binding, and emit the correct error message. + */ +enum class BindingSource +{ + Match, + Let, + For, + /* Closure param or function param */ + Param +}; + +class BindingLayer +{ + BindingSource source; + std::vector<Binding> bindings; + + bool bind_test (Identifier ident, Binding::Kind kind); + +public: + void push (Binding::Kind kind); + + BindingLayer (BindingSource source); + + /** + * Identifies if the identifier has been used in a product binding context. + * eg. `let (a, a) = test();` + */ + bool is_and_bound (Identifier ident); + + /** + * Identifies if the identifier has been used in a or context. + * eg. `let (a, 1) | (a, 2) = test()` + */ + bool is_or_bound (Identifier ident); + + void insert_ident (Identifier ident); + + void merge (); + + BindingSource get_source () const; +}; + // Now our resolver, which keeps track of all the `ForeverStack`s we could want class NameResolutionContext { @@ -171,9 +229,15 @@ public: tl::expected<NodeId, DuplicateNameError> insert (Identifier name, NodeId id, Namespace ns); + tl::expected<NodeId, DuplicateNameError> insert_variant (Identifier name, + NodeId id); + tl::expected<NodeId, DuplicateNameError> insert_shadowable (Identifier name, NodeId id, Namespace ns); + tl::expected<NodeId, DuplicateNameError> + insert_globbed (Identifier name, NodeId id, Namespace ns); + /** * Run a lambda in a "scoped" context, meaning that a new `Rib` will be pushed * before executing the lambda and then popped. This is useful for all kinds @@ -181,8 +245,8 @@ public: * function. This variant of the function enters a new scope in *all* * namespaces, while the second variant enters a scope in *one* namespace. * - * @param rib New `Rib` to create when entering this scope. A function `Rib`, - * or an item `Rib`... etc + * @param rib_kind New `Rib` to create when entering this scope. A function + * `Rib`, or an item `Rib`... etc * @param scope_id node ID of the scope we are entering, e.g the block's * `NodeId`. * @param lambda Function to run within that scope @@ -192,9 +256,10 @@ public: */ // FIXME: Do we want to handle something in particular for expected within the // scoped lambda? - void scoped (Rib rib, NodeId scope_id, std::function<void (void)> lambda, + void scoped (Rib::Kind rib_kind, NodeId scope_id, + std::function<void (void)> lambda, tl::optional<Identifier> path = {}); - void scoped (Rib rib, Namespace ns, NodeId scope_id, + void scoped (Rib::Kind rib_kind, Namespace ns, NodeId scope_id, std::function<void (void)> lambda, tl::optional<Identifier> path = {}); @@ -204,12 +269,127 @@ public: ForeverStack<Namespace::Labels> labels; Analysis::Mappings &mappings; + StackedContexts<BindingLayer> bindings; // TODO: Rename // TODO: Use newtype pattern for Usage and Definition void map_usage (Usage usage, Definition definition); - tl::optional<NodeId> lookup (NodeId usage); + tl::optional<NodeId> lookup (NodeId usage) const; + + template <typename S> + tl::optional<Rib::Definition> + resolve_path (const std::vector<S> &segments, + bool has_opening_scope_resolution, + std::vector<Error> &collect_errors, Namespace ns) + { + std::function<void (const S &, NodeId)> insert_segment_resolution + = [this] (const S &seg, NodeId id) { + auto seg_id = unwrap_segment_node_id (seg); + if (resolved_nodes.find (Usage (seg_id)) == resolved_nodes.end ()) + map_usage (Usage (seg_id), Definition (id)); + }; + switch (ns) + { + case Namespace::Values: + return values.resolve_path (segments, has_opening_scope_resolution, + insert_segment_resolution, collect_errors); + case Namespace::Types: + return types.resolve_path (segments, has_opening_scope_resolution, + insert_segment_resolution, collect_errors); + case Namespace::Macros: + return macros.resolve_path (segments, has_opening_scope_resolution, + insert_segment_resolution, collect_errors); + case Namespace::Labels: + return labels.resolve_path (segments, has_opening_scope_resolution, + insert_segment_resolution, collect_errors); + default: + rust_unreachable (); + } + } + + template <typename S, typename... Args> + tl::optional<Rib::Definition> + resolve_path (const std::vector<S> &segments, + bool has_opening_scope_resolution, + tl::optional<std::vector<Error> &> collect_errors, + Namespace ns_first, Args... ns_args) + { + std::initializer_list<Namespace> namespaces = {ns_first, ns_args...}; + + for (auto ns : namespaces) + { + std::vector<Error> collect_errors_inner; + if (auto ret = resolve_path (segments, has_opening_scope_resolution, + collect_errors_inner, ns)) + return ret; + if (!collect_errors_inner.empty ()) + { + if (collect_errors.has_value ()) + { + std::move (collect_errors_inner.begin (), + collect_errors_inner.end (), + std::back_inserter (collect_errors.value ())); + } + else + { + for (auto &e : collect_errors_inner) + e.emit (); + } + return tl::nullopt; + } + } + + return tl::nullopt; + } + + template <typename... Args> + tl::optional<Rib::Definition> + resolve_path (const AST::SimplePath &path, + tl::optional<std::vector<Error> &> collect_errors, + Namespace ns_first, Args... ns_args) + { + return resolve_path (path.get_segments (), + path.has_opening_scope_resolution (), collect_errors, + ns_first, ns_args...); + } + + template <typename... Args> + tl::optional<Rib::Definition> + resolve_path (const AST::PathInExpression &path, + tl::optional<std::vector<Error> &> collect_errors, + Namespace ns_first, Args... ns_args) + { + return resolve_path (path.get_segments (), path.opening_scope_resolution (), + collect_errors, ns_first, ns_args...); + } + + template <typename... Args> + tl::optional<Rib::Definition> + resolve_path (const AST::TypePath &path, + tl::optional<std::vector<Error> &> collect_errors, + Namespace ns_first, Args... ns_args) + { + return resolve_path (path.get_segments (), + path.has_opening_scope_resolution_op (), + collect_errors, ns_first, ns_args...); + } + + template <typename P, typename... Args> + tl::optional<Rib::Definition> resolve_path (const P &path, Namespace ns_first, + Args... ns_args) + { + return resolve_path (path, tl::nullopt, ns_first, ns_args...); + } + + template <typename P, typename... Args> + tl::optional<Rib::Definition> + resolve_path (const P &path_segments, bool has_opening_scope_resolution, + Namespace ns_first, Args... ns_args) + { + return resolve_path (path_segments, has_opening_scope_resolution, + tl::nullopt, ns_first, ns_args...); + } private: /* Map of "usage" nodes which have been resolved to a "definition" node */ diff --git a/gcc/rust/resolve/rust-name-resolver.cc b/gcc/rust/resolve/rust-name-resolver.cc index ee52e5c..dddaa07 100644 --- a/gcc/rust/resolve/rust-name-resolver.cc +++ b/gcc/rust/resolve/rust-name-resolver.cc @@ -19,6 +19,9 @@ #include "rust-name-resolver.h" #include "rust-ast-full.h" +// for flag_name_resolution_2_0 +#include "options.h" + namespace Rust { namespace Resolver { @@ -429,11 +432,13 @@ Resolver::generate_builtins () setup_builtin ("isize", isize); setup_builtin ("char", char_tyty); setup_builtin ("str", str); - setup_builtin ("!", never); + + // never type + NodeId never_node_id = setup_builtin ("!", never); + set_never_type_node_id (never_node_id); // unit type () - TyTy::TupleType *unit_tyty - = TyTy::TupleType::get_unit_type (mappings.get_next_hir_id ()); + TyTy::TupleType *unit_tyty = TyTy::TupleType::get_unit_type (); std::vector<std::unique_ptr<AST::Type> > elems; AST::TupleType *unit_type = new AST::TupleType (std::move (elems), BUILTINS_LOCATION); @@ -443,7 +448,7 @@ Resolver::generate_builtins () set_unit_type_node_id (unit_type->get_node_id ()); } -void +NodeId Resolver::setup_builtin (const std::string &name, TyTy::BaseType *tyty) { AST::PathIdentSegment seg (name, BUILTINS_LOCATION); @@ -459,11 +464,16 @@ Resolver::setup_builtin (const std::string &name, TyTy::BaseType *tyty) mappings.insert_canonical_path ( builtin_type->get_node_id (), CanonicalPath::new_seg (builtin_type->get_node_id (), name)); + + return builtin_type->get_node_id (); } void Resolver::insert_resolved_name (NodeId refId, NodeId defId) { + rust_assert (!flag_name_resolution_2_0); + rust_assert (resolved_names.find (refId) == resolved_names.end ()); + resolved_names[refId] = defId; get_name_scope ().append_reference_for_def (refId, defId); insert_captured_item (defId); @@ -472,6 +482,7 @@ Resolver::insert_resolved_name (NodeId refId, NodeId defId) bool Resolver::lookup_resolved_name (NodeId refId, NodeId *defId) { + rust_assert (!flag_name_resolution_2_0); auto it = resolved_names.find (refId); if (it == resolved_names.end ()) return false; @@ -483,8 +494,8 @@ Resolver::lookup_resolved_name (NodeId refId, NodeId *defId) void Resolver::insert_resolved_type (NodeId refId, NodeId defId) { - // auto it = resolved_types.find (refId); - // rust_assert (it == resolved_types.end ()); + rust_assert (!flag_name_resolution_2_0); + rust_assert (resolved_types.find (refId) == resolved_types.end ()); resolved_types[refId] = defId; get_type_scope ().append_reference_for_def (refId, defId); @@ -493,6 +504,7 @@ Resolver::insert_resolved_type (NodeId refId, NodeId defId) bool Resolver::lookup_resolved_type (NodeId refId, NodeId *defId) { + rust_assert (!flag_name_resolution_2_0); auto it = resolved_types.find (refId); if (it == resolved_types.end ()) return false; @@ -504,6 +516,7 @@ Resolver::lookup_resolved_type (NodeId refId, NodeId *defId) void Resolver::insert_resolved_label (NodeId refId, NodeId defId) { + rust_assert (!flag_name_resolution_2_0); auto it = resolved_labels.find (refId); rust_assert (it == resolved_labels.end ()); @@ -514,6 +527,7 @@ Resolver::insert_resolved_label (NodeId refId, NodeId defId) bool Resolver::lookup_resolved_label (NodeId refId, NodeId *defId) { + rust_assert (!flag_name_resolution_2_0); auto it = resolved_labels.find (refId); if (it == resolved_labels.end ()) return false; @@ -525,6 +539,7 @@ Resolver::lookup_resolved_label (NodeId refId, NodeId *defId) void Resolver::insert_resolved_macro (NodeId refId, NodeId defId) { + rust_assert (!flag_name_resolution_2_0); auto it = resolved_macros.find (refId); rust_assert (it == resolved_macros.end ()); @@ -535,6 +550,7 @@ Resolver::insert_resolved_macro (NodeId refId, NodeId defId) bool Resolver::lookup_resolved_macro (NodeId refId, NodeId *defId) { + rust_assert (!flag_name_resolution_2_0); auto it = resolved_macros.find (refId); if (it == resolved_macros.end ()) return false; @@ -546,6 +562,7 @@ Resolver::lookup_resolved_macro (NodeId refId, NodeId *defId) void Resolver::insert_resolved_misc (NodeId refId, NodeId defId) { + rust_assert (!flag_name_resolution_2_0); auto it = misc_resolved_items.find (refId); rust_assert (it == misc_resolved_items.end ()); @@ -555,6 +572,7 @@ Resolver::insert_resolved_misc (NodeId refId, NodeId defId) bool Resolver::lookup_resolved_misc (NodeId refId, NodeId *defId) { + rust_assert (!flag_name_resolution_2_0); auto it = misc_resolved_items.find (refId); if (it == misc_resolved_items.end ()) return false; @@ -657,6 +675,8 @@ Resolver::decl_needs_capture (NodeId decl_rib_node_id, const std::set<NodeId> & Resolver::get_captures (NodeId id) const { + rust_assert (!flag_name_resolution_2_0); + auto it = closures_capture_mappings.find (id); rust_assert (it != closures_capture_mappings.end ()); return it->second; diff --git a/gcc/rust/resolve/rust-name-resolver.h b/gcc/rust/resolve/rust-name-resolver.h index c34002e..a3b34a9 100644 --- a/gcc/rust/resolve/rust-name-resolver.h +++ b/gcc/rust/resolve/rust-name-resolver.h @@ -163,9 +163,13 @@ public: Scope &get_macro_scope () { return macro_scope; } NodeId get_global_type_node_id () { return global_type_node_id; } + void set_unit_type_node_id (NodeId id) { unit_ty_node_id = id; } NodeId get_unit_type_node_id () { return unit_ty_node_id; } + void set_never_type_node_id (NodeId id) { never_ty_node_id = id; } + NodeId get_never_type_node_id () { return never_ty_node_id; } + void push_new_module_scope (NodeId module_id) { current_module_stack.push_back (module_id); @@ -200,6 +204,41 @@ public: void insert_captured_item (NodeId id); const std::set<NodeId> &get_captures (NodeId id) const; + std::string as_debug_string () const + { + std::stringstream ss; + + ss << "Names:\n"; + for (auto &n : name_ribs) + { + ss << "\tNodeID: " << n.first << " Rib: " << n.second->debug_str () + << "\n"; + } + ss << "Types:\n"; + for (auto &n : type_ribs) + { + ss << "\tNodeID: " << n.first << " Rib: " << n.second->debug_str () + << "\n"; + } + ss << "Macros:\n"; + + for (auto &n : macro_ribs) + { + ss << "\tNodeID: " << n.first << " Rib: " << n.second->debug_str () + << "\n"; + } + + ss << "Labels:\n"; + + for (auto &n : label_ribs) + { + ss << "\tNodeID: " << n.first << " Rib: " << n.second->debug_str () + << "\n"; + } + + return ss.str (); + } + protected: bool decl_needs_capture (NodeId decl_rib_node_id, NodeId closure_rib_node_id, const Scope &scope); @@ -208,7 +247,7 @@ private: Resolver (); void generate_builtins (); - void setup_builtin (const std::string &name, TyTy::BaseType *tyty); + NodeId setup_builtin (const std::string &name, TyTy::BaseType *tyty); Analysis::Mappings &mappings; TypeCheckContext *tyctx; @@ -222,6 +261,7 @@ private: NodeId global_type_node_id; NodeId unit_ty_node_id; + NodeId never_ty_node_id; // map a AST Node to a Rib std::map<NodeId, Rib *> name_ribs; diff --git a/gcc/rust/resolve/rust-rib.cc b/gcc/rust/resolve/rust-rib.cc index 0a8fce3..690bde9 100644 --- a/gcc/rust/resolve/rust-rib.cc +++ b/gcc/rust/resolve/rust-rib.cc @@ -22,41 +22,81 @@ namespace Rust { namespace Resolver2_0 { -Rib::Definition::Definition (NodeId id, bool shadowable) - : ids ({id}), shadowable (shadowable) -{} +Rib::Definition::Definition (NodeId id, Mode mode, bool enum_variant) + : enum_variant (enum_variant) +{ + switch (mode) + { + case Mode::SHADOWABLE: + ids_shadowable.push_back (id); + return; + case Mode::NON_SHADOWABLE: + ids_non_shadowable.push_back (id); + return; + case Mode::GLOBBED: + ids_globbed.push_back (id); + return; + default: + gcc_unreachable (); + } +} bool Rib::Definition::is_ambiguous () const { - return shadowable && ids.size () > 1; + if (!ids_shadowable.empty ()) + return false; + else if (!ids_non_shadowable.empty ()) + return ids_non_shadowable.size () > 1; + else + return ids_globbed.size () > 1; +} + +bool +Rib::Definition::is_variant () const +{ + return enum_variant; } std::string Rib::Definition::to_string () const { std::stringstream out; - out << (shadowable ? "(S)" : "(NS)") << "["; - std::string sep; - for (auto id : ids) + const char *headers[3] = {"(S)[", "] (NS)[", "] (G)["}; + const std::vector<NodeId> *id_lists[3] + = {&ids_shadowable, &ids_non_shadowable, &ids_globbed}; + for (int i = 0; i < 3; i++) { - out << sep << id; - sep = ","; + out << headers[i]; + std::string sep; + for (auto id : *id_lists[i]) + { + out << sep << id; + sep = ","; + } } out << "]"; + if (enum_variant) + out << "(enum variant)"; return out.str (); } Rib::Definition Rib::Definition::Shadowable (NodeId id) { - return Definition (id, true); + return Definition (id, Mode::SHADOWABLE, false); } Rib::Definition -Rib::Definition::NonShadowable (NodeId id) +Rib::Definition::NonShadowable (NodeId id, bool enum_variant) { - return Definition (id, false); + return Definition (id, Mode::NON_SHADOWABLE, enum_variant); +} + +Rib::Definition +Rib::Definition::Globbed (NodeId id) +{ + return Definition (id, Mode::GLOBBED, false); } DuplicateNameError::DuplicateNameError (std::string name, NodeId existing) @@ -85,29 +125,53 @@ Rib::insert (std::string name, Definition def) /* No old value */ values[name] = def; } - else if (it->second.shadowable && def.shadowable) - { /* Both shadowable */ + else if (it->second.ids_non_shadowable.empty () + || def.ids_non_shadowable.empty ()) + { /* No non-shadowable conflict */ auto ¤t = values[name]; - for (auto id : def.ids) + for (auto id : def.ids_non_shadowable) { - if (std::find (current.ids.cbegin (), current.ids.cend (), id) - == current.ids.cend ()) - { - current.ids.push_back (id); - } + if (std::find (current.ids_non_shadowable.cbegin (), + current.ids_non_shadowable.cend (), id) + == current.ids_non_shadowable.cend ()) + current.ids_non_shadowable.push_back (id); + else + // TODO: should this produce an error? + return tl::make_unexpected (DuplicateNameError (name, id)); + } + for (auto id : def.ids_shadowable) + { + if (std::find (current.ids_shadowable.cbegin (), + current.ids_shadowable.cend (), id) + == current.ids_shadowable.cend ()) + current.ids_shadowable.push_back (id); + else + // TODO: should this produce an error? + return tl::make_unexpected (DuplicateNameError (name, id)); + } + for (auto id : def.ids_globbed) + { + if (std::find (current.ids_globbed.cbegin (), + current.ids_globbed.cend (), id) + == current.ids_globbed.cend ()) + current.ids_globbed.push_back (id); + else + // TODO: should this produce an error? + return tl::make_unexpected (DuplicateNameError (name, id)); } } - else if (it->second.shadowable) - { /* Only old shadowable : replace value */ - values[name] = def; - } - else /* Neither are shadowable */ + else /* Multiple non-shadowable */ { return tl::make_unexpected ( - DuplicateNameError (name, it->second.ids.back ())); + DuplicateNameError (name, it->second.ids_non_shadowable.back ())); } - return def.ids.back (); + if (!def.ids_shadowable.empty ()) + return def.ids_shadowable.back (); + else if (!def.ids_non_shadowable.empty ()) + return def.ids_non_shadowable.back (); + rust_assert (!def.ids_globbed.empty ()); + return def.ids_globbed.back (); } tl::optional<Rib::Definition> diff --git a/gcc/rust/resolve/rust-rib.h b/gcc/rust/resolve/rust-rib.h index 3228a3c..c498328 100644 --- a/gcc/rust/resolve/rust-rib.h +++ b/gcc/rust/resolve/rust-rib.h @@ -111,29 +111,61 @@ public: class Definition { public: - static Definition NonShadowable (NodeId id); + static Definition NonShadowable (NodeId id, bool enum_variant = false); static Definition Shadowable (NodeId id); - - std::vector<NodeId> ids; - bool shadowable; + static Definition Globbed (NodeId id); + + // checked shadowable -> non_shadowable -> globbed + // we have shadowable *and* globbed in order to control + // resolution priority + // we *could* use a single vector with 2 indices here + // but it's probably not worth it for now + std::vector<NodeId> ids_shadowable; + std::vector<NodeId> ids_non_shadowable; + std::vector<NodeId> ids_globbed; + + // Enum variant should be skipped when dealing with inner definition. + // struct E2; + // + // enum MyEnum<T> /* <-- Should be kept */{ + // E2 /* <-- Should be skipped */ (E2); + // } + bool enum_variant; Definition () = default; Definition &operator= (const Definition &) = default; Definition (Definition const &) = default; + bool is_variant () const; + bool is_ambiguous () const; - NodeId get_node_id () + NodeId get_node_id () const { + if (!ids_shadowable.empty ()) + return ids_shadowable.back (); + rust_assert (!is_ambiguous ()); - return ids[0]; + + if (!ids_non_shadowable.empty ()) + return ids_non_shadowable.back (); + + rust_assert (!ids_globbed.empty ()); + return ids_globbed.back (); } std::string to_string () const; private: - Definition (NodeId id, bool shadowable); + enum class Mode + { + SHADOWABLE, + NON_SHADOWABLE, + GLOBBED + }; + + Definition (NodeId id, Mode mode, bool enum_variant); }; enum class Kind @@ -151,8 +183,42 @@ public: ForwardTypeParamBan, /* Const generic, as in the following example: fn foo<T, const X: T>() {} */ ConstParamType, + /* Prelude rib, used for both the language prelude (i32,usize,etc) and the + * (future) {std,core}::prelude::* import. A regular rib with the + * restriction that you cannot `use` items from the Prelude + */ + Prelude, } kind; + static std::string kind_to_string (Rib::Kind kind) + { + switch (kind) + { + case Rib::Kind::Normal: + return "Normal"; + case Rib::Kind::Module: + return "Module"; + case Rib::Kind::Function: + return "Function"; + case Rib::Kind::ConstantItem: + return "ConstantItem"; + case Rib::Kind::TraitOrImpl: + return "TraitOrImpl"; + case Rib::Kind::Item: + return "Item"; + case Rib::Kind::Closure: + return "Closure"; + case Rib::Kind::MacroDefinition: + return "Macro definition"; + case Rib::Kind::ForwardTypeParamBan: + return "Forward type param ban"; + case Rib::Kind::ConstParamType: + return "Const Param Type"; + default: + rust_unreachable (); + } + } + Rib (Kind kind); Rib (Kind kind, std::string identifier, NodeId id); Rib (Kind kind, std::unordered_map<std::string, NodeId> values); diff --git a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc index 746b224..2f036fe 100644 --- a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc +++ b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc @@ -26,109 +26,47 @@ namespace Rust { namespace Resolver2_0 { -void -GlobbingVisitor::go (AST::Module *module) -{ - for (auto &i : module->get_items ()) - visit (i); -} - -void -GlobbingVisitor::visit (AST::Module &module) -{ - if (module.get_visibility ().is_public ()) - ctx.insert_shadowable (module.get_name (), module.get_node_id (), - Namespace::Types); -} - -void -GlobbingVisitor::visit (AST::MacroRulesDefinition ¯o) -{ - if (macro.get_visibility ().is_public ()) - ctx.insert_shadowable (macro.get_rule_name (), macro.get_node_id (), - Namespace::Macros); -} - -void -GlobbingVisitor::visit (AST::Function &function) -{ - if (function.get_visibility ().is_public ()) - ctx.insert_shadowable (function.get_function_name (), - function.get_node_id (), Namespace::Values); -} - -void -GlobbingVisitor::visit (AST::StaticItem &static_item) -{ - if (static_item.get_visibility ().is_public ()) - ctx.insert_shadowable (static_item.get_identifier (), - static_item.get_node_id (), Namespace::Values); -} +TopLevel::TopLevel (NameResolutionContext &resolver) + : DefaultResolver (resolver), dirty (false) +{} +template <typename T> void -GlobbingVisitor::visit (AST::StructStruct &struct_item) +TopLevel::insert_enum_variant_or_error_out (const Identifier &identifier, + const T &node) { - if (struct_item.get_visibility ().is_public ()) - { - ctx.insert_shadowable (struct_item.get_identifier (), - struct_item.get_node_id (), Namespace::Types); - if (struct_item.is_unit_struct ()) - ctx.insert_shadowable (struct_item.get_identifier (), - struct_item.get_node_id (), Namespace::Values); - } + insert_enum_variant_or_error_out (identifier, node.get_locus (), + node.get_node_id ()); } void -GlobbingVisitor::visit (AST::TupleStruct &tuple_struct) +TopLevel::check_multiple_insertion_error ( + tl::expected<NodeId, DuplicateNameError> result, const Identifier &identifier, + const location_t &locus, const NodeId node_id) { - if (tuple_struct.get_visibility ().is_public ()) + if (result) + dirty = true; + else if (result.error ().existing != node_id) { - ctx.insert_shadowable (tuple_struct.get_identifier (), - tuple_struct.get_node_id (), Namespace::Types); + rich_location rich_loc (line_table, locus); + rich_loc.add_range (node_locations[result.error ().existing]); - ctx.insert_shadowable (tuple_struct.get_identifier (), - tuple_struct.get_node_id (), Namespace::Values); + rust_error_at (rich_loc, ErrorCode::E0428, "%qs defined multiple times", + identifier.as_string ().c_str ()); } } - void -GlobbingVisitor::visit (AST::Enum &enum_item) +TopLevel::insert_enum_variant_or_error_out (const Identifier &identifier, + const location_t &locus, + const NodeId node_id) { - if (enum_item.get_visibility ().is_public ()) - ctx.insert_shadowable (enum_item.get_identifier (), - enum_item.get_node_id (), Namespace::Types); -} - -void -GlobbingVisitor::visit (AST::Union &union_item) -{ - if (union_item.get_visibility ().is_public ()) - ctx.insert_shadowable (union_item.get_identifier (), - union_item.get_node_id (), Namespace::Values); -} - -void -GlobbingVisitor::visit (AST::ConstantItem &const_item) -{ - if (const_item.get_visibility ().is_public ()) - ctx.insert_shadowable (const_item.get_identifier (), - const_item.get_node_id (), Namespace::Values); -} - -void -GlobbingVisitor::visit (AST::ExternCrate &crate) -{} + // keep track of each node's location to provide useful errors + node_locations.emplace (node_id, locus); -void -GlobbingVisitor::visit (AST::UseDeclaration &use) -{ - // Handle cycles ? + auto result = ctx.insert_variant (identifier, node_id); + check_multiple_insertion_error (result, identifier, locus, node_id); } -TopLevel::TopLevel (NameResolutionContext &resolver) - : DefaultResolver (resolver) -{} - template <typename T> void TopLevel::insert_or_error_out (const Identifier &identifier, const T &node, @@ -146,15 +84,7 @@ TopLevel::insert_or_error_out (const Identifier &identifier, node_locations.emplace (node_id, locus); auto result = ctx.insert (identifier, node_id, ns); - - if (!result && result.error ().existing != node_id) - { - rich_location rich_loc (line_table, locus); - rich_loc.add_range (node_locations[result.error ().existing]); - - rust_error_at (rich_loc, ErrorCode::E0428, "%qs defined multiple times", - identifier.as_string ().c_str ()); - } + check_multiple_insertion_error (result, identifier, locus, node_id); } void @@ -174,13 +104,28 @@ TopLevel::visit (AST::Module &module) { insert_or_error_out (module.get_name (), module, Namespace::Types); - auto sub_visitor = [this, &module] () { - for (auto &item : module.get_items ()) - item->accept_vis (*this); - }; + // Parse the module's items if they haven't been expanded and the file + // should be parsed (i.e isn't hidden behind an untrue or impossible cfg + // directive + // TODO: make sure this is right + // TODO: avoid loading items if cfg attributes are present? + // might not be needed if this runs after early resolution? + // This was copied from the old early resolver method + // 'accumulate_escaped_macros' + if (module.get_kind () == AST::Module::UNLOADED) + { + module.load_items (); - ctx.scoped (Rib::Kind::Module, module.get_node_id (), sub_visitor, - module.get_name ()); + // If the module was previously unloaded, then we don't want to visit it + // this time around as the CfgStrip hasn't run on its inner items yet. + // Skip it for now, mark the visitor as dirty and try again + + dirty = true; + + return; + } + + DefaultResolver::visit (module); if (Analysis::Mappings::get ().lookup_ast_module (module.get_node_id ()) == tl::nullopt) @@ -190,26 +135,50 @@ TopLevel::visit (AST::Module &module) void TopLevel::visit (AST::Trait &trait) { - // FIXME: This Self injection is dodgy. It even lead to issues with metadata - // export in the past (#2349). We cannot tell appart injected parameters from - // regular ones. Dumping generic parameters highlights this Self in metadata, - // during debug or proc macro collection. This is clearly a hack. - // - // For now I'll keep it here in the new name resolver even if it should - // probably not be there. We need to find another way to solve this. - // Maybe an additional attribute to Trait ? - // - // From old resolver: - //// we need to inject an implicit self TypeParam here - //// FIXME: which location should be used for Rust::Identifier `Self`? - AST::TypeParam *implicit_self - = new AST::TypeParam ({"Self"}, trait.get_locus ()); - trait.insert_implict_self ( - std::unique_ptr<AST::GenericParam> (implicit_self)); + insert_or_error_out (trait.get_identifier (), trait, Namespace::Types); DefaultResolver::visit (trait); } +void +TopLevel::visit (AST::InherentImpl &impl) +{ + auto inner_fn = [this, &impl] () { + insert_or_error_out (Identifier ("Self", impl.get_type ().get_locus ()), + impl.get_type (), Namespace::Types); + + // We do want to visit with the default visitor instead of default resolver + // because we don't want to insert the scope twice. + AST::DefaultASTVisitor::visit (impl); + }; + + ctx.scoped (Rib::Kind::TraitOrImpl, impl.get_node_id (), inner_fn); +} + +void +TopLevel::visit (AST::TraitImpl &impl) +{ + auto inner_fn = [this, &impl] () { + insert_or_error_out (Identifier ("Self", impl.get_type ().get_locus ()), + impl.get_type (), Namespace::Types); + + // We do want to visit using the default visitor instead of default resolver + // because we don't want to insert the scope twice. + AST::DefaultASTVisitor::visit (impl); + }; + + ctx.scoped (Rib::Kind::TraitOrImpl, impl.get_node_id (), inner_fn); +} + +void +TopLevel::visit (AST::TraitItemType &trait_item) +{ + insert_or_error_out (trait_item.get_identifier ().as_string (), trait_item, + Namespace::Types); + + DefaultResolver::visit (trait_item); +} + template <typename PROC_MACRO> static void insert_macros (std::vector<PROC_MACRO> ¯os, NameResolutionContext &ctx) @@ -231,7 +200,16 @@ void TopLevel::visit (AST::ExternCrate &crate) { auto &mappings = Analysis::Mappings::get (); - CrateNum num = *mappings.lookup_crate_name (crate.get_referenced_crate ()); + auto num_opt = mappings.lookup_crate_name (crate.get_referenced_crate ()); + + if (!num_opt) + { + rust_error_at (crate.get_locus (), "unknown crate %qs", + crate.get_referenced_crate ().c_str ()); + return; + } + + CrateNum num = *num_opt; auto attribute_macros = mappings.lookup_attribute_proc_macros (num); @@ -323,34 +301,35 @@ TopLevel::visit (AST::Function &function) } void -TopLevel::visit (AST::BlockExpr &expr) +TopLevel::visit (AST::StaticItem &static_item) { - // extracting the lambda from the `scoped` call otherwise the code looks like - // a hot turd thanks to our .clang-format - - auto sub_vis = [this, &expr] () { - for (auto &stmt : expr.get_statements ()) - stmt->accept_vis (*this); - - if (expr.has_tail_expr ()) - expr.get_tail_expr ().accept_vis (*this); - }; + insert_or_error_out (static_item.get_identifier (), static_item, + Namespace::Values); - ctx.scoped (Rib::Kind::Normal, expr.get_node_id (), sub_vis); + DefaultResolver::visit (static_item); } void -TopLevel::visit (AST::StaticItem &static_item) +TopLevel::visit (AST::ExternalStaticItem &static_item) { - auto sub_vis - = [this, &static_item] () { static_item.get_expr ().accept_vis (*this); }; + insert_or_error_out (static_item.get_identifier ().as_string (), static_item, + Namespace::Values); - ctx.scoped (Rib::Kind::Item, static_item.get_node_id (), sub_vis); + DefaultResolver::visit (static_item); } void TopLevel::visit (AST::StructStruct &struct_item) { + auto generic_vis = [this, &struct_item] () { + for (auto &g : struct_item.get_generic_params ()) + { + g->accept_vis (*this); + } + }; + + ctx.scoped (Rib::Kind::Item, struct_item.get_node_id (), generic_vis); + insert_or_error_out (struct_item.get_struct_name (), struct_item, Namespace::Types); @@ -363,6 +342,23 @@ TopLevel::visit (AST::StructStruct &struct_item) } void +TopLevel::visit (AST::TypeParam &type_param) +{ + insert_or_error_out (type_param.get_type_representation (), type_param, + Namespace::Types); + + DefaultResolver::visit (type_param); +} + +void +TopLevel::visit (AST::ConstGenericParam &const_param) +{ + insert_or_error_out (const_param.get_name (), const_param, Namespace::Values); + + DefaultResolver::visit (const_param); +} + +void TopLevel::visit (AST::TupleStruct &tuple_struct) { insert_or_error_out (tuple_struct.get_struct_name (), tuple_struct, @@ -370,24 +366,26 @@ TopLevel::visit (AST::TupleStruct &tuple_struct) insert_or_error_out (tuple_struct.get_struct_name (), tuple_struct, Namespace::Values); + + DefaultResolver::visit (tuple_struct); } void TopLevel::visit (AST::EnumItem &variant) { - insert_or_error_out (variant.get_identifier (), variant, Namespace::Types); + insert_enum_variant_or_error_out (variant.get_identifier (), variant); } void TopLevel::visit (AST::EnumItemTuple &variant) { - insert_or_error_out (variant.get_identifier (), variant, Namespace::Types); + insert_enum_variant_or_error_out (variant.get_identifier (), variant); } void TopLevel::visit (AST::EnumItemStruct &variant) { - insert_or_error_out (variant.get_identifier (), variant, Namespace::Types); + insert_enum_variant_or_error_out (variant.get_identifier (), variant); } void @@ -402,13 +400,7 @@ TopLevel::visit (AST::Enum &enum_item) insert_or_error_out (enum_item.get_identifier (), enum_item, Namespace::Types); - auto field_vis = [this, &enum_item] () { - for (auto &variant : enum_item.get_variants ()) - variant->accept_vis (*this); - }; - - ctx.scoped (Rib::Kind::Item /* FIXME: Is that correct? */, - enum_item.get_node_id (), field_vis, enum_item.get_identifier ()); + DefaultResolver::visit (enum_item); } void @@ -416,6 +408,8 @@ TopLevel::visit (AST::Union &union_item) { insert_or_error_out (union_item.get_identifier (), union_item, Namespace::Types); + + DefaultResolver::visit (union_item); } void @@ -427,181 +421,13 @@ TopLevel::visit (AST::ConstantItem &const_item) DefaultResolver::visit (const_item); } -bool -TopLevel::handle_use_glob (AST::SimplePath &glob) -{ - auto resolved = ctx.types.resolve_path (glob.get_segments ()); - if (!resolved.has_value ()) - return false; - - auto result - = Analysis::Mappings::get ().lookup_ast_module (resolved->get_node_id ()); - - if (!result.has_value ()) - return false; - - GlobbingVisitor gvisitor (ctx); - gvisitor.go (result.value ()); - - return true; -} - -bool -TopLevel::handle_use_dec (AST::SimplePath &path) -{ - auto locus = path.get_final_segment ().get_locus (); - auto declared_name = path.get_final_segment ().as_string (); - - // in what namespace do we perform path resolution? All of them? see which one - // matches? Error out on ambiguities? - // so, apparently, for each one that matches, add it to the proper namespace - // :( - - auto found = false; - - auto resolve_and_insert - = [this, &found, &declared_name, locus] (Namespace ns, - const AST::SimplePath &path) { - tl::optional<Rib::Definition> resolved = tl::nullopt; - - // FIXME: resolve_path needs to return an `expected<NodeId, Error>` so - // that we can improve it with hints or location or w/ever. and maybe - // only emit it the first time. - switch (ns) - { - case Namespace::Values: - resolved = ctx.values.resolve_path (path.get_segments ()); - break; - case Namespace::Types: - resolved = ctx.types.resolve_path (path.get_segments ()); - break; - case Namespace::Macros: - resolved = ctx.macros.resolve_path (path.get_segments ()); - break; - case Namespace::Labels: - // TODO: Is that okay? - rust_unreachable (); - } - - // FIXME: Ugly - (void) resolved.map ([this, &found, &declared_name, locus, ns, - path] (Rib::Definition def) { - found = true; - - // what do we do with the id? - insert_or_error_out (declared_name, locus, def.get_node_id (), ns); - auto result = node_forwarding.find (def.get_node_id ()); - if (result != node_forwarding.cend () - && result->second != path.get_node_id ()) - rust_error_at (path.get_locus (), "%qs defined multiple times", - declared_name.c_str ()); - else // No previous thing has inserted this into our scope - node_forwarding.insert ({def.get_node_id (), path.get_node_id ()}); - - return def.get_node_id (); - }); - }; - - resolve_and_insert (Namespace::Values, path); - resolve_and_insert (Namespace::Types, path); - resolve_and_insert (Namespace::Macros, path); - - return found; -} - -bool -TopLevel::handle_rebind (std::pair<AST::SimplePath, AST::UseTreeRebind> &rebind) +void +TopLevel::visit (AST::TypeAlias &type_item) { - auto &path = rebind.first; - - location_t locus = UNKNOWN_LOCATION; - std::string declared_name; - - switch (rebind.second.get_new_bind_type ()) - { - case AST::UseTreeRebind::NewBindType::IDENTIFIER: - declared_name = rebind.second.get_identifier ().as_string (); - locus = rebind.second.get_identifier ().get_locus (); - break; - case AST::UseTreeRebind::NewBindType::NONE: - declared_name = path.get_final_segment ().as_string (); - locus = path.get_final_segment ().get_locus (); - break; - case AST::UseTreeRebind::NewBindType::WILDCARD: - rust_unreachable (); - break; - } - - // in what namespace do we perform path resolution? All - // of them? see which one matches? Error out on - // ambiguities? so, apparently, for each one that - // matches, add it to the proper namespace - // :( - auto found = false; - - auto resolve_and_insert = [this, &found, &declared_name, - locus] (Namespace ns, - const AST::SimplePath &path) { - tl::optional<Rib::Definition> resolved = tl::nullopt; - tl::optional<Rib::Definition> resolved_bind = tl::nullopt; - - std::vector<AST::SimplePathSegment> declaration_v - = {AST::SimplePathSegment (declared_name, locus)}; - // FIXME: resolve_path needs to return an `expected<NodeId, Error>` so - // that we can improve it with hints or location or w/ever. and maybe - // only emit it the first time. - switch (ns) - { - case Namespace::Values: - resolved = ctx.values.resolve_path (path.get_segments ()); - resolved_bind = ctx.values.resolve_path (declaration_v); - break; - case Namespace::Types: - resolved = ctx.types.resolve_path (path.get_segments ()); - resolved_bind = ctx.types.resolve_path (declaration_v); - break; - case Namespace::Macros: - resolved = ctx.macros.resolve_path (path.get_segments ()); - resolved_bind = ctx.macros.resolve_path (declaration_v); - break; - case Namespace::Labels: - // TODO: Is that okay? - rust_unreachable (); - } - - resolved.map ([this, &found, &declared_name, locus, ns, path, - &resolved_bind] (Rib::Definition def) { - found = true; - - insert_or_error_out (declared_name, locus, def.get_node_id (), ns); - if (resolved_bind.has_value ()) - { - auto bind_def = resolved_bind.value (); - // what do we do with the id? - auto result = node_forwarding.find (bind_def.get_node_id ()); - if (result != node_forwarding.cend () - && result->second != path.get_node_id ()) - rust_error_at (path.get_locus (), "%qs defined multiple times", - declared_name.c_str ()); - } - else - { - // No previous thing has inserted this into our scope - node_forwarding.insert ({def.get_node_id (), path.get_node_id ()}); - } - return def.get_node_id (); - }); - }; - - // do this for all namespaces (even Labels?) - - resolve_and_insert (Namespace::Values, path); - resolve_and_insert (Namespace::Types, path); - resolve_and_insert (Namespace::Macros, path); - - // TODO: No labels? No, right? + insert_or_error_out (type_item.get_new_type_name (), type_item, + Namespace::Types); - return found; + DefaultResolver::visit (type_item); } static void @@ -721,6 +547,8 @@ flatten_glob (const AST::UseTreeGlob &glob, std::vector<AST::SimplePath> &paths, { if (glob.has_path ()) paths.emplace_back (glob.get_path ()); + else + paths.emplace_back (AST::SimplePath ({}, false, glob.get_locus ())); } void @@ -731,6 +559,10 @@ TopLevel::visit (AST::UseDeclaration &use) auto rebind_path = std::vector<std::pair<AST::SimplePath, AST::UseTreeRebind>> (); + auto &values_rib = ctx.values.peek (); + auto &types_rib = ctx.types.peek (); + auto ¯os_rib = ctx.macros.peek (); + // FIXME: How do we handle `use foo::{self}` imports? Some beforehand cleanup? // How do we handle module imports in general? Should they get added to all // namespaces? @@ -738,21 +570,22 @@ TopLevel::visit (AST::UseDeclaration &use) const auto &tree = use.get_tree (); flatten (tree.get (), paths, glob_path, rebind_path, this->ctx); - for (auto &path : paths) - if (!handle_use_dec (path)) - rust_error_at (path.get_final_segment ().get_locus (), ErrorCode::E0433, - "unresolved import %qs", path.as_string ().c_str ()); - - for (auto &glob : glob_path) - if (!handle_use_glob (glob)) - rust_error_at (glob.get_final_segment ().get_locus (), ErrorCode::E0433, - "unresolved import %qs", glob.as_string ().c_str ()); - - for (auto &rebind : rebind_path) - if (!handle_rebind (rebind)) - rust_error_at (rebind.first.get_final_segment ().get_locus (), - ErrorCode::E0433, "unresolved import %qs", - rebind.first.as_string ().c_str ()); + auto imports = std::vector<ImportKind> (); + + for (auto &&path : paths) + imports.emplace_back ( + ImportKind::Simple (std::move (path), values_rib, types_rib, macros_rib)); + + for (auto &&glob : glob_path) + imports.emplace_back ( + ImportKind::Glob (std::move (glob), values_rib, types_rib, macros_rib)); + + for (auto &&rebind : rebind_path) + imports.emplace_back ( + ImportKind::Rebind (std::move (rebind.first), std::move (rebind.second), + values_rib, types_rib, macros_rib)); + + imports_to_resolve.insert ({use.get_node_id (), std::move (imports)}); } } // namespace Resolver2_0 diff --git a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h index 0950370..3ff37ed 100644 --- a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h +++ b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h @@ -19,36 +19,16 @@ #ifndef RUST_TOPLEVEL_NAME_RESOLVER_2_0_H #define RUST_TOPLEVEL_NAME_RESOLVER_2_0_H +#include "optional.h" #include "rust-ast-visitor.h" +#include "rust-ast.h" +#include "rust-item.h" #include "rust-name-resolution-context.h" #include "rust-default-resolver.h" namespace Rust { namespace Resolver2_0 { -class GlobbingVisitor : public AST::DefaultASTVisitor -{ - using AST::DefaultASTVisitor::visit; - -public: - GlobbingVisitor (NameResolutionContext &ctx) : ctx (ctx) {} - - void go (AST::Module *module); - void visit (AST::Module &module) override; - void visit (AST::MacroRulesDefinition ¯o) override; - void visit (AST::Function &function) override; - void visit (AST::StaticItem &static_item) override; - void visit (AST::StructStruct &struct_item) override; - void visit (AST::TupleStruct &tuple_struct) override; - void visit (AST::Enum &enum_item) override; - void visit (AST::Union &union_item) override; - void visit (AST::ConstantItem &const_item) override; - void visit (AST::ExternCrate &crate) override; - void visit (AST::UseDeclaration &use) override; - -private: - NameResolutionContext &ctx; -}; /** * The `TopLevel` visitor takes care of collecting all the definitions in a * crate, and inserting them into the proper namespaces. These definitions can @@ -63,10 +43,84 @@ public: void go (AST::Crate &crate); -private: + bool is_dirty () { return dirty; } + + // Each import will be transformed into an instance of `ImportKind`, a class + // representing some of the data we need to resolve in the + // `EarlyNameResolver`. Basically, for each `UseTree` that we see in + // `TopLevel`, create one of these. `TopLevel` should build a list of these + // `ImportKind`s, which `Early` can then resolve to their proper definitions. + // Then, a final pass will insert the definitions into the `ForeverStack` - + // `FinalizeImports`. + // + // Using this struct should be very simple - each path within a `UseTree` + // becomes one `ImportKind`. The complex case is glob imports, in which case + // one glob import will become one `ImportKind` which will later become + // multiple definitions thanks to the `GlobbingVisitor`. + struct ImportKind + { + enum class Kind + { + Glob, + Simple, + Rebind, + } kind; + + static ImportKind Glob (AST::SimplePath &&to_resolve, Rib &values_rib, + Rib &types_rib, Rib ¯os_rib) + { + return ImportKind (Kind::Glob, std::move (to_resolve), values_rib, + types_rib, macros_rib); + } + + static ImportKind Simple (AST::SimplePath &&to_resolve, Rib &values_rib, + Rib &types_rib, Rib ¯os_rib) + { + return ImportKind (Kind::Simple, std::move (to_resolve), values_rib, + types_rib, macros_rib); + } + + static ImportKind Rebind (AST::SimplePath &&to_resolve, + AST::UseTreeRebind &&rebind, Rib &values_rib, + Rib &types_rib, Rib ¯os_rib) + { + return ImportKind (Kind::Rebind, std::move (to_resolve), values_rib, + types_rib, macros_rib, std::move (rebind)); + } + + // The path for `Early` to resolve. + AST::SimplePath to_resolve; + + // The path to rebind an import to - only present if kind is Kind::Rebind + tl::optional<AST::UseTreeRebind> rebind; + + Rib &values_rib; + Rib &types_rib; + Rib ¯os_rib; + + private: + ImportKind (Kind kind, AST::SimplePath &&to_resolve, Rib &values_rib, + Rib &types_rib, Rib ¯os_rib, + tl::optional<AST::UseTreeRebind> &&rebind = tl::nullopt) + : kind (kind), to_resolve (std::move (to_resolve)), + rebind (std::move (rebind)), values_rib (values_rib), + types_rib (types_rib), macros_rib (macros_rib) + {} + }; + + std::unordered_map<NodeId, std::vector<ImportKind>> &get_imports_to_resolve () + { + return imports_to_resolve; + } + + void check_multiple_insertion_error ( + tl::expected<NodeId, DuplicateNameError> result, + const Identifier &identifier, const location_t &locus, + const NodeId node_id); + /** - * Insert a new definition or error out if a definition with the same name was - * already present in the same namespace in the same scope. + * Insert a new definition or error out if a definition with the same name + * was already present in the same namespace in the same scope. * * @param identifier The identifier of the definition to add. * @param node A reference to the node, so we can get its `NodeId` and @@ -80,19 +134,39 @@ private: const location_t &locus, const NodeId &id, Namespace ns); + template <typename T> + void insert_enum_variant_or_error_out (const Identifier &identifier, + const T &node); + + void insert_enum_variant_or_error_out (const Identifier &identifier, + const location_t &locus, + const NodeId node_id); + +private: + // If a new export has been defined whilst visiting the visitor is considered + // dirty + bool dirty; + // FIXME: Do we move these to our mappings? std::unordered_map<NodeId, location_t> node_locations; // Store node forwarding for use declaration, the link between a - // "new" local name and its definition. + // definition and its new local name. std::unordered_map<NodeId, NodeId> node_forwarding; + // One of the outputs of the `TopLevel` visitor - the list of imports that + // `Early` should take care of resolving + std::unordered_map<NodeId, std::vector<ImportKind>> imports_to_resolve; + void visit (AST::Module &module) override; void visit (AST::Trait &trait) override; + void visit (AST::InherentImpl &impl) override; + void visit (AST::TraitImpl &impl) override; + void visit (AST::TraitItemType &trait_item) override; void visit (AST::MacroRulesDefinition ¯o) override; void visit (AST::Function &function) override; - void visit (AST::BlockExpr &expr) override; void visit (AST::StaticItem &static_item) override; + void visit (AST::ExternalStaticItem &static_item) override; void visit (AST::StructStruct &struct_item) override; void visit (AST::TupleStruct &tuple_struct) override; void visit (AST::EnumItem &variant) override; @@ -102,15 +176,10 @@ private: void visit (AST::Enum &enum_item) override; void visit (AST::Union &union_item) override; void visit (AST::ConstantItem &const_item) override; + void visit (AST::TypeAlias &type_item) override; void visit (AST::ExternCrate &crate) override; - - // FIXME: Documentation - // Call this on all the paths of a UseDec - so each flattened path in a - // UseTreeList for example - // FIXME: Should that return `found`? - bool handle_use_dec (AST::SimplePath &path); - bool handle_use_glob (AST::SimplePath &glob); - bool handle_rebind (std::pair<AST::SimplePath, AST::UseTreeRebind> &pair); + void visit (AST::TypeParam &type_param) override; + void visit (AST::ConstGenericParam &const_param) override; void visit (AST::UseDeclaration &use) override; }; @@ -118,4 +187,17 @@ private: } // namespace Resolver2_0 } // namespace Rust +// For storing Imports as keys in maps +namespace std { +template <> struct less<Rust::Resolver2_0::TopLevel::ImportKind> +{ + bool operator() (const Rust::Resolver2_0::TopLevel::ImportKind &lhs, + const Rust::Resolver2_0::TopLevel::ImportKind &rhs) const + { + return lhs.to_resolve.as_string () < rhs.to_resolve.as_string () + && lhs.kind < rhs.kind; + } +}; +} // namespace std + #endif // !RUST_TOPLEVEL_NAME_RESOLVER_2_0_H diff --git a/gcc/rust/rust-backend.h b/gcc/rust/rust-backend.h index 9d28cf6..414799e 100644 --- a/gcc/rust/rust-backend.h +++ b/gcc/rust/rust-backend.h @@ -133,11 +133,11 @@ function_ptr_type (tree result, const std::vector<tree> &praameters, // Get a struct type. tree -struct_type (const std::vector<typed_identifier> &fields); +struct_type (const std::vector<typed_identifier> &fields, bool layout = true); // Get a union type. tree -union_type (const std::vector<typed_identifier> &fields); +union_type (const std::vector<typed_identifier> &fields, bool layout = true); // Get an array type. tree @@ -496,7 +496,7 @@ write_global_definitions (const std::vector<tree> &type_decls, // TODO: make static tree -fill_in_fields (tree, const std::vector<typed_identifier> &); +fill_in_fields (tree, const std::vector<typed_identifier> &, bool); tree fill_in_array (tree, tree, tree); diff --git a/gcc/rust/rust-gcc.cc b/gcc/rust/rust-gcc.cc index 273ab78..e5319d3 100644 --- a/gcc/rust/rust-gcc.cc +++ b/gcc/rust/rust-gcc.cc @@ -61,7 +61,7 @@ tree Bvariable::get_tree (location_t location) const { - if (this->t_ == error_mark_node) + if (error_operand_p (this->t_)) return error_mark_node; TREE_USED (this->t_) = 1; @@ -431,7 +431,7 @@ float_type (int bits) tree pointer_type (tree to_type) { - if (to_type == error_mark_node) + if (error_operand_p (to_type)) return error_mark_node; tree type = build_pointer_type (to_type); return type; @@ -442,7 +442,7 @@ pointer_type (tree to_type) tree reference_type (tree to_type) { - if (to_type == error_mark_node) + if (error_operand_p (to_type)) return error_mark_node; tree type = build_reference_type (to_type); return type; @@ -453,7 +453,7 @@ reference_type (tree to_type) tree immutable_type (tree base) { - if (base == error_mark_node) + if (error_operand_p (base)) return error_mark_node; tree constified = build_qualified_type (base, TYPE_QUAL_CONST); return constified; @@ -472,17 +472,16 @@ function_type (const typed_identifier &receiver, if (receiver.type != NULL_TREE) { tree t = receiver.type; - if (t == error_mark_node) + if (error_operand_p (t)) return error_mark_node; *pp = tree_cons (NULL_TREE, t, NULL_TREE); pp = &TREE_CHAIN (*pp); } - for (std::vector<typed_identifier>::const_iterator p = parameters.begin (); - p != parameters.end (); ++p) + for (const auto &p : parameters) { - tree t = p->type; - if (t == error_mark_node) + tree t = p.type; + if (error_operand_p (t)) return error_mark_node; *pp = tree_cons (NULL_TREE, t, NULL_TREE); pp = &TREE_CHAIN (*pp); @@ -502,11 +501,11 @@ function_type (const typed_identifier &receiver, gcc_assert (result_struct != NULL); result = result_struct; } - if (result == error_mark_node) + if (error_operand_p (result)) return error_mark_node; tree fntype = build_function_type (result, args); - if (fntype == error_mark_node) + if (error_operand_p (fntype)) return error_mark_node; return build_pointer_type (fntype); @@ -521,21 +520,16 @@ function_type_variadic (const typed_identifier &receiver, size_t n = parameters.size () + (receiver.type != NULL_TREE ? 1 : 0); tree *args = XALLOCAVEC (tree, n); size_t offs = 0; + if (error_operand_p (receiver.type)) + return error_mark_node; if (receiver.type != NULL_TREE) - { - tree t = receiver.type; - if (t == error_mark_node) - return error_mark_node; - - args[offs++] = t; - } + args[offs++] = receiver.type; - for (std::vector<typed_identifier>::const_iterator p = parameters.begin (); - p != parameters.end (); ++p) + for (const auto &p : parameters) { - tree t = p->type; - if (t == error_mark_node) + tree t = p.type; + if (error_operand_p (t)) return error_mark_node; args[offs++] = t; } @@ -550,11 +544,11 @@ function_type_variadic (const typed_identifier &receiver, gcc_assert (result_struct != NULL_TREE); result = result_struct; } - if (result == error_mark_node) + if (error_operand_p (result)) return error_mark_node; tree fntype = build_varargs_function_type_array (result, n, args); - if (fntype == error_mark_node) + if (error_operand_p (fntype)) return error_mark_node; return build_pointer_type (fntype); @@ -569,7 +563,7 @@ function_ptr_type (tree result_type, const std::vector<tree> ¶meters, for (auto ¶m : parameters) { - if (param == error_mark_node) + if (error_operand_p (param)) return error_mark_node; *pp = tree_cons (NULL_TREE, param, NULL_TREE); @@ -583,7 +577,7 @@ function_ptr_type (tree result_type, const std::vector<tree> ¶meters, result = void_type_node; tree fntype = build_function_type (result, args); - if (fntype == error_mark_node) + if (error_operand_p (fntype)) return error_mark_node; return build_pointer_type (fntype); @@ -592,40 +586,42 @@ function_ptr_type (tree result_type, const std::vector<tree> ¶meters, // Make a struct type. tree -struct_type (const std::vector<typed_identifier> &fields) +struct_type (const std::vector<typed_identifier> &fields, bool layout) { - return fill_in_fields (make_node (RECORD_TYPE), fields); + return fill_in_fields (make_node (RECORD_TYPE), fields, layout); } // Make a union type. tree -union_type (const std::vector<typed_identifier> &fields) +union_type (const std::vector<typed_identifier> &fields, bool layout) { - return fill_in_fields (make_node (UNION_TYPE), fields); + return fill_in_fields (make_node (UNION_TYPE), fields, layout); } // Fill in the fields of a struct or union type. tree -fill_in_fields (tree fill, const std::vector<typed_identifier> &fields) +fill_in_fields (tree fill, const std::vector<typed_identifier> &fields, + bool layout) { tree field_trees = NULL_TREE; tree *pp = &field_trees; - for (std::vector<typed_identifier>::const_iterator p = fields.begin (); - p != fields.end (); ++p) + for (const auto &p : fields) { - tree name_tree = get_identifier_from_string (p->name); - tree type_tree = p->type; - if (type_tree == error_mark_node) + tree name_tree = get_identifier_from_string (p.name); + tree type_tree = p.type; + if (error_operand_p (type_tree)) return error_mark_node; - tree field = build_decl (p->location, FIELD_DECL, name_tree, type_tree); + tree field = build_decl (p.location, FIELD_DECL, name_tree, type_tree); DECL_CONTEXT (field) = fill; *pp = field; pp = &DECL_CHAIN (field); } TYPE_FIELDS (fill) = field_trees; - layout_type (fill); + + if (layout) + layout_type (fill); // Because Rust permits converting between named struct types and // equivalent struct types, for which we use VIEW_CONVERT_EXPR, and @@ -649,7 +645,7 @@ array_type (tree element_type, tree length) tree fill_in_array (tree fill, tree element_type, tree length_tree) { - if (element_type == error_mark_node || length_tree == error_mark_node) + if (error_operand_p (element_type) || error_operand_p (length_tree)) return error_mark_node; gcc_assert (TYPE_SIZE (element_type) != NULL_TREE); @@ -681,7 +677,7 @@ fill_in_array (tree fill, tree element_type, tree length_tree) tree named_type (const std::string &name, tree type, location_t location) { - if (type == error_mark_node) + if (error_operand_p (type)) return error_mark_node; // The middle-end expects a basic type to have a name. In Rust every @@ -711,7 +707,7 @@ named_type (const std::string &name, tree type, location_t location) int64_t type_size (tree t) { - if (t == error_mark_node) + if (error_operand_p (t)) return 1; if (t == void_type_node) return 0; @@ -729,7 +725,7 @@ type_size (tree t) int64_t type_alignment (tree t) { - if (t == error_mark_node) + if (error_operand_p (t)) return 1; return TYPE_ALIGN_UNIT (t); } @@ -739,7 +735,7 @@ type_alignment (tree t) int64_t type_field_alignment (tree t) { - if (t == error_mark_node) + if (error_operand_p (t)) return 1; return rust_field_alignment (t); } @@ -749,7 +745,7 @@ type_field_alignment (tree t) int64_t type_field_offset (tree struct_tree, size_t index) { - if (struct_tree == error_mark_node) + if (error_operand_p (struct_tree)) return 0; gcc_assert (TREE_CODE (struct_tree) == RECORD_TYPE); tree field = TYPE_FIELDS (struct_tree); @@ -770,7 +766,7 @@ tree zero_expression (tree t) { tree ret; - if (t == error_mark_node) + if (error_operand_p (t)) ret = error_mark_node; else ret = build_zero_cst (t); @@ -791,7 +787,7 @@ tree float_constant_expression (tree t, mpfr_t val) { tree ret; - if (t == error_mark_node) + if (error_operand_p (t)) return error_mark_node; REAL_VALUE_TYPE r1; @@ -842,8 +838,7 @@ boolean_constant_expression (bool val) tree convert_expression (tree type_tree, tree expr_tree, location_t location) { - if (type_tree == error_mark_node || expr_tree == error_mark_node - || TREE_TYPE (expr_tree) == error_mark_node) + if (error_operand_p (type_tree) || error_operand_p (expr_tree)) return error_mark_node; tree ret; @@ -875,8 +870,7 @@ convert_expression (tree type_tree, tree expr_tree, location_t location) tree struct_field_expression (tree struct_tree, size_t index, location_t location) { - if (struct_tree == error_mark_node - || TREE_TYPE (struct_tree) == error_mark_node) + if (error_operand_p (struct_tree)) return error_mark_node; gcc_assert (TREE_CODE (TREE_TYPE (struct_tree)) == RECORD_TYPE || TREE_CODE (TREE_TYPE (struct_tree)) == UNION_TYPE); @@ -892,7 +886,7 @@ struct_field_expression (tree struct_tree, size_t index, location_t location) field = DECL_CHAIN (field); gcc_assert (field != NULL_TREE); } - if (TREE_TYPE (field) == error_mark_node) + if (error_operand_p (TREE_TYPE (field))) return error_mark_node; tree ret = fold_build3_loc (location, COMPONENT_REF, TREE_TYPE (field), struct_tree, field, NULL_TREE); @@ -906,7 +900,7 @@ struct_field_expression (tree struct_tree, size_t index, location_t location) tree compound_expression (tree stat, tree expr, location_t location) { - if (stat == error_mark_node || expr == error_mark_node) + if (error_operand_p (stat) || error_operand_p (expr)) return error_mark_node; tree ret = fold_build2_loc (location, COMPOUND_EXPR, TREE_TYPE (expr), stat, expr); @@ -920,8 +914,8 @@ tree conditional_expression (tree, tree type_tree, tree cond_expr, tree then_expr, tree else_expr, location_t location) { - if (type_tree == error_mark_node || cond_expr == error_mark_node - || then_expr == error_mark_node || else_expr == error_mark_node) + if (error_operand_p (type_tree) || error_operand_p (cond_expr) + || error_operand_p (then_expr) || error_operand_p (else_expr)) return error_mark_node; tree ret = build3_loc (location, COND_EXPR, type_tree, cond_expr, then_expr, else_expr); @@ -939,7 +933,7 @@ operator_to_tree_code (NegationOperator op) case NegationOperator::NEGATE: return NEGATE_EXPR; case NegationOperator::NOT: - return TRUTH_NOT_EXPR; + return BIT_NOT_EXPR; default: rust_unreachable (); } @@ -1018,12 +1012,12 @@ operator_to_tree_code (LazyBooleanOperator op) } } -/* Helper function for deciding if a tree is a floating point node. */ +/* Returns true if the type of EXP is a floating point type. + False otherwise. */ bool -is_floating_point (tree t) +is_floating_point (tree exp) { - auto tree_type = TREE_CODE (TREE_TYPE (t)); - return tree_type == REAL_TYPE || tree_type == COMPLEX_TYPE; + return FLOAT_TYPE_P (TREE_TYPE (exp)); } // Return an expression for the negation operation OP EXPR. @@ -1032,7 +1026,7 @@ negation_expression (NegationOperator op, tree expr_tree, location_t location) { /* Check if the expression is an error, in which case we return an error expression. */ - if (expr_tree == error_mark_node || TREE_TYPE (expr_tree) == error_mark_node) + if (error_operand_p (expr_tree)) return error_mark_node; /* For negation operators, the resulting type should be the same as its @@ -1068,9 +1062,15 @@ arithmetic_or_logical_expression (ArithmeticOrLogicalOperator op, tree left, { /* Check if either expression is an error, in which case we return an error expression. */ - if (left == error_mark_node || right == error_mark_node) + if (error_operand_p (left) || error_operand_p (right)) return error_mark_node; + // unwrap the const decls if set + if (TREE_CODE (left) == CONST_DECL) + left = DECL_INITIAL (left); + if (TREE_CODE (right) == CONST_DECL) + right = DECL_INITIAL (right); + /* We need to determine if we're doing floating point arithmetics of integer arithmetics. */ bool floating_point = is_floating_point (left); @@ -1103,6 +1103,18 @@ arithmetic_or_logical_expression (ArithmeticOrLogicalOperator op, tree left, if (floating_point && extended_type != NULL_TREE) ret = convert (original_type, ret); + if (op == ArithmeticOrLogicalOperator::DIVIDE + && (integer_zerop (right) || fixed_zerop (right))) + { + rust_error_at (location, "division by zero"); + } + else if (op == ArithmeticOrLogicalOperator::LEFT_SHIFT + && TREE_CODE (right) == INTEGER_CST + && (compare_tree_int (right, TYPE_PRECISION (TREE_TYPE (ret))) >= 0)) + { + rust_error_at (location, "left shift count >= width of type"); + } + return ret; } @@ -1162,7 +1174,7 @@ arithmetic_or_logical_expression_checked (ArithmeticOrLogicalOperator op, { /* Check if either expression is an error, in which case we return an error expression. */ - if (left == error_mark_node || right == error_mark_node) + if (error_operand_p (left) || error_operand_p (right)) return error_mark_node; // FIXME: Add `if (!debug_mode)` @@ -1202,7 +1214,7 @@ comparison_expression (ComparisonOperator op, tree left_tree, tree right_tree, { /* Check if either expression is an error, in which case we return an error expression. */ - if (left_tree == error_mark_node || right_tree == error_mark_node) + if (error_operand_p (left_tree) || error_operand_p (right_tree)) return error_mark_node; /* For comparison operators, the resulting type should be boolean. */ @@ -1222,7 +1234,7 @@ lazy_boolean_expression (LazyBooleanOperator op, tree left_tree, { /* Check if either expression is an error, in which case we return an error expression. */ - if (left_tree == error_mark_node || right_tree == error_mark_node) + if (error_operand_p (left_tree) || error_operand_p (right_tree)) return error_mark_node; /* For lazy boolean operators, the resulting type should be the same as the @@ -1243,7 +1255,7 @@ constructor_expression (tree type_tree, bool is_variant, const std::vector<tree> &vals, int union_index, location_t location) { - if (type_tree == error_mark_node) + if (error_operand_p (type_tree)) return error_mark_node; vec<constructor_elt, va_gc> *init; @@ -1285,8 +1297,8 @@ constructor_expression (tree type_tree, bool is_variant, gcc_assert (field != NULL_TREE); field = DECL_CHAIN (field); } - if (TREE_TYPE (field) == error_mark_node || val == error_mark_node - || TREE_TYPE (val) == error_mark_node) + + if (TREE_TYPE (field) == error_mark_node || error_operand_p (val)) return error_mark_node; if (int_size_in_bytes (TREE_TYPE (field)) == 0) @@ -1316,8 +1328,7 @@ constructor_expression (tree type_tree, bool is_variant, { gcc_assert (field != NULL_TREE); tree val = (*p); - if (TREE_TYPE (field) == error_mark_node || val == error_mark_node - || TREE_TYPE (val) == error_mark_node) + if (TREE_TYPE (field) == error_mark_node || error_operand_p (val)) return error_mark_node; if (int_size_in_bytes (TREE_TYPE (field)) == 0) @@ -1338,7 +1349,7 @@ constructor_expression (tree type_tree, bool is_variant, if (!TREE_CONSTANT (elt->value)) is_constant = false; } - gcc_assert (field == NULL_TREE); + // gcc_assert (field == NULL_TREE); } } @@ -1356,7 +1367,7 @@ array_constructor_expression (tree type_tree, const std::vector<tree> &vals, location_t location) { - if (type_tree == error_mark_node) + if (error_operand_p (type_tree)) return error_mark_node; gcc_assert (indexes.size () == vals.size ()); @@ -1373,7 +1384,7 @@ array_constructor_expression (tree type_tree, tree index = size_int (indexes[i]); tree val = vals[i]; - if (index == error_mark_node || val == error_mark_node) + if (error_operand_p (index) || error_operand_p (val)) return error_mark_node; if (element_size == 0) @@ -1477,8 +1488,7 @@ array_initializer (tree fndecl, tree block, tree array_type, tree length, tree array_index_expression (tree array_tree, tree index_tree, location_t location) { - if (array_tree == error_mark_node || TREE_TYPE (array_tree) == error_mark_node - || index_tree == error_mark_node) + if (error_operand_p (array_tree) || error_operand_p (index_tree)) return error_mark_node; // A function call that returns a zero sized object will have been @@ -1500,7 +1510,7 @@ tree call_expression (tree fn, const std::vector<tree> &fn_args, tree chain_expr, location_t location) { - if (fn == error_mark_node || TREE_TYPE (fn) == error_mark_node) + if (error_operand_p (fn)) return error_mark_node; gcc_assert (FUNCTION_POINTER_TYPE_P (TREE_TYPE (fn))); @@ -1580,7 +1590,7 @@ tree init_statement (tree, Bvariable *var, tree init_tree) { tree var_tree = var->get_decl (); - if (var_tree == error_mark_node || init_tree == error_mark_node) + if (error_operand_p (var_tree) || error_operand_p (init_tree)) return error_mark_node; gcc_assert (TREE_CODE (var_tree) == VAR_DECL); @@ -1611,7 +1621,7 @@ init_statement (tree, Bvariable *var, tree init_tree) tree assignment_statement (tree lhs, tree rhs, location_t location) { - if (lhs == error_mark_node || rhs == error_mark_node) + if (error_operand_p (lhs) || error_operand_p (rhs)) return error_mark_node; // To avoid problems with GNU ld, we don't make zero-sized @@ -1636,14 +1646,14 @@ assignment_statement (tree lhs, tree rhs, location_t location) tree return_statement (tree fntree, tree val, location_t location) { - if (fntree == error_mark_node) + if (error_operand_p (fntree)) return error_mark_node; tree result = DECL_RESULT (fntree); - if (result == error_mark_node) + if (error_operand_p (result)) return error_mark_node; - if (val == error_mark_node) + if (error_operand_p (val)) return error_mark_node; tree set @@ -1661,8 +1671,8 @@ tree exception_handler_statement (tree try_stmt, tree except_stmt, tree finally_stmt, location_t location) { - if (try_stmt == error_mark_node || except_stmt == error_mark_node - || finally_stmt == error_mark_node) + if (error_operand_p (try_stmt) || error_operand_p (except_stmt) + || error_operand_p (finally_stmt)) return error_mark_node; if (except_stmt != NULL_TREE) @@ -1681,8 +1691,8 @@ tree if_statement (tree, tree cond_tree, tree then_tree, tree else_tree, location_t location) { - if (cond_tree == error_mark_node || then_tree == error_mark_node - || else_tree == error_mark_node) + if (error_operand_p (cond_tree) || error_operand_p (then_tree) + || error_operand_p (else_tree)) return error_mark_node; tree ret = build3_loc (location, COND_EXPR, void_type_node, cond_tree, then_tree, else_tree); @@ -1708,15 +1718,12 @@ exit_expression (tree cond_tree, location_t locus) tree compound_statement (tree s1, tree s2) { - tree stmt_list = NULL_TREE; - tree t = s1; - if (t == error_mark_node) - return error_mark_node; - append_to_statement_list (t, &stmt_list); - t = s2; - if (t == error_mark_node) + if (error_operand_p (s1) || error_operand_p (s2)) return error_mark_node; - append_to_statement_list (t, &stmt_list); + + tree stmt_list = NULL_TREE; + append_to_statement_list (s1, &stmt_list); + append_to_statement_list (s2, &stmt_list); // If neither statement has any side effects, stmt_list can be NULL // at this point. @@ -1732,11 +1739,9 @@ tree statement_list (const std::vector<tree> &statements) { tree stmt_list = NULL_TREE; - for (std::vector<tree>::const_iterator p = statements.begin (); - p != statements.end (); ++p) + for (tree t : statements) { - tree t = (*p); - if (t == error_mark_node) + if (error_operand_p (t)) return error_mark_node; append_to_statement_list (t, &stmt_list); } @@ -1788,12 +1793,13 @@ block (tree fndecl, tree enclosing, const std::vector<Bvariable *> &vars, *pp = block_tree; } + // Chain the variables of the scope together so they are all connected + // to the block. tree *pp = &BLOCK_VARS (block_tree); - for (std::vector<Bvariable *>::const_iterator pv = vars.begin (); - pv != vars.end (); ++pv) + for (Bvariable *bv : vars) { - *pp = (*pv)->get_decl (); - if (*pp != error_mark_node) + *pp = bv->get_decl (); + if (!error_operand_p (*pp)) pp = &DECL_CHAIN (*pp); } *pp = NULL_TREE; @@ -1812,11 +1818,9 @@ void block_add_statements (tree bind_tree, const std::vector<tree> &statements) { tree stmt_list = NULL_TREE; - for (std::vector<tree>::const_iterator p = statements.begin (); - p != statements.end (); ++p) + for (tree s : statements) { - tree s = (*p); - if (s != error_mark_node) + if (!error_operand_p (s)) append_to_statement_list (s, &stmt_list); } @@ -1894,8 +1898,7 @@ convert_tree (tree type_tree, tree expr_tree, location_t location) if (type_tree == TREE_TYPE (expr_tree)) return expr_tree; - if (type_tree == error_mark_node || expr_tree == error_mark_node - || TREE_TYPE (expr_tree) == error_mark_node) + if (error_operand_p (type_tree) || error_operand_p (expr_tree)) return error_mark_node; if (POINTER_TYPE_P (type_tree) || INTEGRAL_TYPE_P (type_tree) @@ -1924,7 +1927,7 @@ global_variable (const std::string &var_name, const std::string &asm_name, tree type_tree, bool is_external, bool is_hidden, bool in_unique_section, location_t location) { - if (type_tree == error_mark_node) + if (error_operand_p (type_tree)) return Bvariable::error_variable (); // The GNU linker does not like dynamic variables with zero size. @@ -1963,11 +1966,11 @@ global_variable (const std::string &var_name, const std::string &asm_name, void global_variable_set_init (Bvariable *var, tree expr_tree) { - if (expr_tree == error_mark_node) + if (error_operand_p (expr_tree)) return; gcc_assert (TREE_CONSTANT (expr_tree)); tree var_decl = var->get_decl (); - if (var_decl == error_mark_node) + if (error_operand_p (var_decl)) return; DECL_INITIAL (var_decl) = expr_tree; @@ -1988,7 +1991,7 @@ Bvariable * local_variable (tree function, const std::string &name, tree type_tree, Bvariable *decl_var, location_t location) { - if (type_tree == error_mark_node) + if (error_operand_p (type_tree)) return Bvariable::error_variable (); tree decl = build_decl (location, VAR_DECL, get_identifier_from_string (name), type_tree); @@ -2009,7 +2012,7 @@ Bvariable * parameter_variable (tree function, const std::string &name, tree type_tree, location_t location) { - if (type_tree == error_mark_node) + if (error_operand_p (type_tree)) return Bvariable::error_variable (); tree decl = build_decl (location, PARM_DECL, get_identifier_from_string (name), type_tree); @@ -2026,7 +2029,7 @@ Bvariable * static_chain_variable (tree fndecl, const std::string &name, tree type_tree, location_t location) { - if (type_tree == error_mark_node) + if (error_operand_p (type_tree)) return Bvariable::error_variable (); tree decl = build_decl (location, PARM_DECL, get_identifier_from_string (name), type_tree); @@ -2060,8 +2063,8 @@ temporary_variable (tree fndecl, tree bind_tree, tree type_tree, tree init_tree, tree *pstatement) { gcc_assert (fndecl != NULL_TREE); - if (type_tree == error_mark_node || init_tree == error_mark_node - || fndecl == error_mark_node) + if (error_operand_p (type_tree) || error_operand_p (init_tree) + || error_operand_p (fndecl)) { *pstatement = error_mark_node; return Bvariable::error_variable (); @@ -2178,13 +2181,13 @@ tree function (tree functype, const std::string &name, const std::string &asm_name, unsigned int flags, location_t location) { - if (functype != error_mark_node) - { - gcc_assert (FUNCTION_POINTER_TYPE_P (functype)); - functype = TREE_TYPE (functype); - } + if (error_operand_p (functype)) + return error_mark_node; + + gcc_assert (FUNCTION_POINTER_TYPE_P (functype)); + functype = TREE_TYPE (functype); tree id = get_identifier_from_string (name); - if (functype == error_mark_node || id == error_mark_node) + if (error_operand_p (id)) return error_mark_node; tree decl = build_decl (location, FUNCTION_DECL, id, functype); @@ -2222,8 +2225,8 @@ tree function_defer_statement (tree function, tree undefer_tree, tree defer_tree, location_t location) { - if (undefer_tree == error_mark_node || defer_tree == error_mark_node - || function == error_mark_node) + if (error_operand_p (undefer_tree) || error_operand_p (defer_tree) + || error_operand_p (function)) return error_mark_node; if (DECL_STRUCT_FUNCTION (function) == NULL) @@ -2255,16 +2258,15 @@ bool function_set_parameters (tree function, const std::vector<Bvariable *> ¶m_vars) { - if (function == error_mark_node) + if (error_operand_p (function)) return false; tree params = NULL_TREE; tree *pp = ¶ms; - for (std::vector<Bvariable *>::const_iterator pv = param_vars.begin (); - pv != param_vars.end (); ++pv) + for (Bvariable *bv : param_vars) { - *pp = (*pv)->get_decl (); - gcc_assert (*pp != error_mark_node); + *pp = bv->get_decl (); + gcc_assert (!error_operand_p (*pp)); pp = &DECL_CHAIN (*pp); } *pp = NULL_TREE; @@ -2289,23 +2291,19 @@ write_global_definitions (const std::vector<tree> &type_decls, // Convert all non-erroneous declarations into Gimple form. size_t i = 0; - for (std::vector<Bvariable *>::const_iterator p = variable_decls.begin (); - p != variable_decls.end (); ++p) + for (Bvariable *bv : variable_decls) { - tree v = (*p)->get_decl (); - if (v != error_mark_node) - { - defs[i] = v; - rust_preserve_from_gc (defs[i]); - ++i; - } + tree v = bv->get_decl (); + if (error_operand_p (v)) + continue; + defs[i] = v; + rust_preserve_from_gc (defs[i]); + ++i; } - for (std::vector<tree>::const_iterator p = type_decls.begin (); - p != type_decls.end (); ++p) + for (tree type_tree : type_decls) { - tree type_tree = (*p); - if (type_tree != error_mark_node && IS_TYPE_OR_DECL_P (type_tree)) + if (!error_operand_p (type_tree) && IS_TYPE_OR_DECL_P (type_tree)) { defs[i] = TYPE_NAME (type_tree); gcc_assert (defs[i] != NULL); @@ -2313,21 +2311,18 @@ write_global_definitions (const std::vector<tree> &type_decls, ++i; } } - for (std::vector<tree>::const_iterator p = constant_decls.begin (); - p != constant_decls.end (); ++p) + for (tree t : constant_decls) { - if ((*p) != error_mark_node) + if (!error_operand_p (t)) { - defs[i] = (*p); + defs[i] = t; rust_preserve_from_gc (defs[i]); ++i; } } - for (std::vector<tree>::const_iterator p = function_decls.begin (); - p != function_decls.end (); ++p) + for (tree decl : function_decls) { - tree decl = (*p); - if (decl != error_mark_node) + if (!error_operand_p (decl)) { rust_preserve_from_gc (decl); if (DECL_STRUCT_FUNCTION (decl) == NULL) diff --git a/gcc/rust/rust-lang.cc b/gcc/rust/rust-lang.cc index b84e114..f3a155d 100644 --- a/gcc/rust/rust-lang.cc +++ b/gcc/rust/rust-lang.cc @@ -143,6 +143,8 @@ grs_langhook_init_options_struct (struct gcc_options *opts) opts->x_warn_unused_result = 1; /* lets warn for infinite recursion*/ opts->x_warn_infinite_recursion = 1; + /* Enable exception handling (aka `panic!` in Rust) */ + opts->x_flag_exceptions = 1; // nothing yet - used by frontends to change specific options for the language Rust::Session::get_instance ().init_options (); diff --git a/gcc/rust/rust-session-manager.cc b/gcc/rust/rust-session-manager.cc index 61a76d6..48acbf34 100644 --- a/gcc/rust/rust-session-manager.cc +++ b/gcc/rust/rust-session-manager.cc @@ -17,7 +17,11 @@ // <http://www.gnu.org/licenses/>. #include "rust-session-manager.h" +#include "rust-collect-lang-items.h" +#include "rust-desugar-for-loops.h" +#include "rust-desugar-question-mark.h" #include "rust-diagnostics.h" +#include "rust-hir-pattern-analysis.h" #include "rust-immutable-name-resolution-context.h" #include "rust-unsafe-checker.h" #include "rust-lex.h" @@ -264,6 +268,9 @@ Session::handle_option ( case OPT_frust_metadata_output_: options.set_metadata_output (arg); break; + case OPT_frust_panic_: + options.set_panic_strategy (flag_rust_panic); + break; default: break; @@ -396,31 +403,16 @@ Session::handle_input_files (int num_files, const char **files) 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); - } - - 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); } void -Session::handle_crate_name (const AST::Crate &parsed_crate) +Session::handle_crate_name (const char *filename, + const AST::Crate &parsed_crate) { auto &mappings = Analysis::Mappings::get (); - auto crate_name_changed = false; + auto crate_name_found = false; auto error = Error (UNDEF_LOCATION, std::string ()); for (const auto &attr : parsed_crate.inner_attrs) @@ -444,7 +436,6 @@ Session::handle_crate_name (const AST::Crate &parsed_crate) continue; } - auto options = Session::get_instance ().options; if (options.crate_name_set_manually && (options.crate_name != msg_str)) { rust_error_at (attr.get_locus (), @@ -452,19 +443,39 @@ Session::handle_crate_name (const AST::Crate &parsed_crate) "required to match, but %qs does not match %qs", options.crate_name.c_str (), msg_str.c_str ()); } - crate_name_changed = true; + crate_name_found = 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)) + options.crate_name_set_manually |= crate_name_found; + if (!options.crate_name_set_manually) { - error.emit (); - rust_inform (linemap_position_for_column (line_table, 0), - "crate name inferred from this file"); + auto crate_name = infer_crate_name (filename); + if (crate_name.empty ()) + { + rust_error_at (UNDEF_LOCATION, "crate name is empty"); + rust_inform (linemap_position_for_column (line_table, 0), + "crate name inferred from this file"); + return; + } + + rust_debug ("inferred crate name: %s", crate_name.c_str ()); + options.set_crate_name (crate_name); + + if (!validate_crate_name (options.get_crate_name (), error)) + { + error.emit (); + rust_inform (linemap_position_for_column (line_table, 0), + "crate name inferred from this file"); + return; + } } + + if (saw_errors ()) + return; + + CrateNum crate_num = mappings.get_next_crate_num (options.get_crate_name ()); + mappings.set_current_crate (crate_num); } // Parses a single file with filename filename. @@ -476,10 +487,11 @@ Session::compile_crate (const char *filename) 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: " + "properly. Most of the errors produced will be the fault of gccrs and " + "not the crate you are trying to compile. Because of this, please report " + "errors directly to us instead of opening issues on said crate's " + "repository.\n\n" + "Our 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" @@ -533,7 +545,7 @@ Session::compile_crate (const char *filename) std::unique_ptr<AST::Crate> ast_crate = parser.parse_crate (); // handle crate name - handle_crate_name (*ast_crate.get ()); + handle_crate_name (filename, *ast_crate.get ()); // dump options except lexer dump if (options.dump_option_enabled (CompileOptions::AST_DUMP_PRETTY)) @@ -598,10 +610,16 @@ Session::compile_crate (const char *filename) if (last_step == CompileOptions::CompileStep::Expansion) return; + AST::CollectLangItems ().go (parsed_crate); + auto name_resolution_ctx = Resolver2_0::NameResolutionContext (); // expansion pipeline stage expansion (parsed_crate, name_resolution_ctx); + + AST::DesugarForLoops ().go (parsed_crate); + AST::DesugarQuestionMark ().go (parsed_crate); + rust_debug ("\033[0;31mSUCCESSFULLY FINISHED EXPANSION \033[0m"); if (options.dump_option_enabled (CompileOptions::EXPANSION_DUMP)) { @@ -671,6 +689,11 @@ Session::compile_crate (const char *filename) if (saw_errors ()) return; + Analysis::PatternChecker ().go (hir); + + if (saw_errors ()) + return; + if (last_step == CompileOptions::CompileStep::Privacy) return; @@ -918,21 +941,24 @@ Session::expansion (AST::Crate &crate, Resolver2_0::NameResolutionContext &ctx) { CfgStrip ().go (crate); // Errors might happen during cfg strip pass - if (saw_errors ()) - break; + bool visitor_dirty = false; if (flag_name_resolution_2_0) { Resolver2_0::Early early (ctx); early.go (crate); macro_errors = early.get_macro_resolve_errors (); + visitor_dirty = early.is_dirty (); } else Resolver::EarlyNameResolver ().go (crate); + if (saw_errors ()) + break; + ExpandVisitor (expander).go (crate); - fixed_point_reached = !expander.has_changed (); + fixed_point_reached = !expander.has_changed () && !visitor_dirty; expander.reset_changed_state (); iterations++; @@ -1384,6 +1410,7 @@ rust_crate_name_validation_test (void) ASSERT_FALSE (Rust::validate_crate_name ("∀", error)); /* Tests for crate name inference */ + ASSERT_EQ (Rust::infer_crate_name (".rs"), ""); 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"); diff --git a/gcc/rust/rust-session-manager.h b/gcc/rust/rust-session-manager.h index b5a715c..83ba121 100644 --- a/gcc/rust/rust-session-manager.h +++ b/gcc/rust/rust-session-manager.h @@ -264,6 +264,13 @@ struct CompileOptions } compile_until = CompileStep::End; + enum class PanicStrategy + { + Unwind, + Abort, + } panic_strategy + = PanicStrategy::Unwind; + bool dump_option_enabled (DumpOption option) const { return dump_options.find (option) != dump_options.end (); @@ -320,6 +327,13 @@ struct CompileOptions const CompileStep &get_compile_until () const { return compile_until; } + void set_panic_strategy (int strategy) + { + panic_strategy = static_cast<PanicStrategy> (strategy); + } + + const PanicStrategy &get_panic_strategy () const { return panic_strategy; } + void set_metadata_output (const std::string &path) { metadata_output_path = path; @@ -376,7 +390,7 @@ public: const struct cl_option_handlers *handlers); void handle_input_files (int num_files, const char **files); void init_options (); - void handle_crate_name (const AST::Crate &parsed_crate); + void handle_crate_name (const char *filename, const AST::Crate &parsed_crate); /* This function saves the filename data into the session manager using the * `move` semantics, and returns a C-style string referencing the input diff --git a/gcc/rust/typecheck/rust-autoderef.cc b/gcc/rust/typecheck/rust-autoderef.cc index 7e80b8e..6aa20a8 100644 --- a/gcc/rust/typecheck/rust-autoderef.cc +++ b/gcc/rust/typecheck/rust-autoderef.cc @@ -113,7 +113,7 @@ Adjuster::try_unsize_type (TyTy::BaseType *ty) auto slice = new TyTy::SliceType (mappings.get_next_hir_id (), ty->get_ident ().locus, TyTy::TyVar (slice_elem->get_ref ())); - context->insert_implicit_type (slice); + context->insert_implicit_type (slice->get_ref (), slice); return Adjustment (Adjustment::AdjustmentType::UNSIZE, ty, slice); } @@ -209,7 +209,7 @@ resolve_operator_overload_fn ( == 0) { TraitReference *trait_reference - = TraitResolver::Lookup (*parent->get_trait_ref ().get ()); + = TraitResolver::Lookup (parent->get_trait_ref ()); if (!trait_reference->is_error ()) { TyTy::BaseType *lookup = nullptr; diff --git a/gcc/rust/typecheck/rust-casts.cc b/gcc/rust/typecheck/rust-casts.cc index 5235069f..90bdef1 100644 --- a/gcc/rust/typecheck/rust-casts.cc +++ b/gcc/rust/typecheck/rust-casts.cc @@ -200,6 +200,26 @@ TypeCastRules::cast_rules () } break; + case TyTy::TypeKind::FLOAT: { + // can only do this for number types not char + bool from_char + = from.get_ty ()->get_kind () == TyTy::TypeKind::CHAR; + if (!from_char) + return TypeCoercionRules::CoercionResult{{}, + to.get_ty ()->clone ()}; + } + break; + + case TyTy::TypeKind::POINTER: { + // char can't be casted as a ptr + bool from_char + = from.get_ty ()->get_kind () == TyTy::TypeKind::CHAR; + if (!from_char) + return TypeCoercionRules::CoercionResult{{}, + to.get_ty ()->clone ()}; + } + break; + case TyTy::TypeKind::INFER: case TyTy::TypeKind::USIZE: case TyTy::TypeKind::ISIZE: @@ -215,6 +235,12 @@ TypeCastRules::cast_rules () case TyTy::TypeKind::FLOAT: switch (to.get_ty ()->get_kind ()) { + case TyTy::TypeKind::USIZE: + case TyTy::TypeKind::ISIZE: + case TyTy::TypeKind::UINT: + case TyTy::TypeKind::INT: + return TypeCoercionRules::CoercionResult{{}, to.get_ty ()->clone ()}; + case TyTy::TypeKind::FLOAT: return TypeCoercionRules::CoercionResult{{}, to.get_ty ()->clone ()}; @@ -244,12 +270,25 @@ TypeCastRules::cast_rules () case TyTy::TypeKind::POINTER: switch (to.get_ty ()->get_kind ()) { + case TyTy::TypeKind::USIZE: + case TyTy::TypeKind::ISIZE: + case TyTy::TypeKind::UINT: + case TyTy::TypeKind::INT: { + // refs should not cast to numeric type + bool from_ptr + = from.get_ty ()->get_kind () == TyTy::TypeKind::POINTER; + if (from_ptr) + { + return TypeCoercionRules::CoercionResult{ + {}, to.get_ty ()->clone ()}; + } + } + break; + case TyTy::TypeKind::REF: case TyTy::TypeKind::POINTER: return check_ptr_ptr_cast (); - // FIXME can you cast a pointer to a integral type? - default: return TypeCoercionRules::CoercionResult::get_error (); } diff --git a/gcc/rust/typecheck/rust-hir-dot-operator.cc b/gcc/rust/typecheck/rust-hir-dot-operator.cc index 8e5473f..c1165e9 100644 --- a/gcc/rust/typecheck/rust-hir-dot-operator.cc +++ b/gcc/rust/typecheck/rust-hir-dot-operator.cc @@ -62,7 +62,7 @@ MethodResolver::Select (std::set<MethodCandidate> &candidates, for (size_t i = 0; i < arguments.size (); i++) { TyTy::BaseType *arg = arguments.at (i); - TyTy::BaseType *param = fn.get_params ().at (i + 1).second; + TyTy::BaseType *param = fn.get_params ().at (i + 1).get_type (); TyTy::BaseType *coerced = try_coercion (0, TyTy::TyWithLocation (param), TyTy::TyWithLocation (arg), UNDEF_LOCATION); @@ -200,104 +200,103 @@ MethodResolver::select (TyTy::BaseType &receiver) }; std::vector<trait_item_candidate> trait_fns; - mappings.iterate_impl_blocks ( - [&] (HirId id, HIR::ImplBlock *impl) mutable -> bool { - bool is_trait_impl = impl->has_trait_ref (); - if (!is_trait_impl) - return true; - - // look for impl implementation else lookup the associated trait item - for (auto &impl_item : impl->get_impl_items ()) - { - bool is_fn = impl_item->get_impl_item_type () - == HIR::ImplItem::ImplItemType::FUNCTION; - if (!is_fn) - continue; - - HIR::Function *func = static_cast<HIR::Function *> (impl_item.get ()); - if (!func->is_method ()) - continue; - - bool name_matches = func->get_function_name ().as_string ().compare ( - segment_name.as_string ()) - == 0; - if (!name_matches) - continue; - - TyTy::BaseType *ty = nullptr; - if (!query_type (func->get_mappings ().get_hirid (), &ty)) - continue; - if (ty->get_kind () == TyTy::TypeKind::ERROR) - continue; - - rust_assert (ty->get_kind () == TyTy::TypeKind::FNDEF); - TyTy::FnType *fnty = static_cast<TyTy::FnType *> (ty); - const TyTy::BaseType *impl_self - = TypeCheckItem::ResolveImplBlockSelf (*impl); - - // see: - // https://gcc-rust.zulipchat.com/#narrow/stream/266897-general/topic/Method.20Resolution/near/338646280 - // https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/method/probe.rs#L650-L660 - bool impl_self_is_ptr - = impl_self->get_kind () == TyTy::TypeKind::POINTER; - bool impl_self_is_ref = impl_self->get_kind () == TyTy::TypeKind::REF; - if (receiver_is_raw_ptr && impl_self_is_ptr) - { - const TyTy::PointerType &sptr - = *static_cast<const TyTy::PointerType *> (impl_self); - const TyTy::PointerType &ptr - = *static_cast<const TyTy::PointerType *> (raw); - - // we could do this via lang-item assemblies if we refactor this - bool mut_match = sptr.mutability () == ptr.mutability (); - if (!mut_match) - continue; - } - else if (receiver_is_ref && impl_self_is_ref) - { - const TyTy::ReferenceType &sptr - = *static_cast<const TyTy::ReferenceType *> (impl_self); - const TyTy::ReferenceType &ptr - = *static_cast<const TyTy::ReferenceType *> (raw); - - // we could do this via lang-item assemblies if we refactor this - bool mut_match = sptr.mutability () == ptr.mutability (); - if (!mut_match) - continue; - } + mappings.iterate_impl_blocks ([&] (HirId id, + HIR::ImplBlock *impl) mutable -> bool { + bool is_trait_impl = impl->has_trait_ref (); + if (!is_trait_impl) + return true; - inherent_impl_fns.push_back ({func, impl, fnty}); - return true; - } + // look for impl implementation else lookup the associated trait item + for (auto &impl_item : impl->get_impl_items ()) + { + bool is_fn = impl_item->get_impl_item_type () + == HIR::ImplItem::ImplItemType::FUNCTION; + if (!is_fn) + continue; + + HIR::Function *func = static_cast<HIR::Function *> (impl_item.get ()); + if (!func->is_method ()) + continue; + + bool name_matches = func->get_function_name ().as_string ().compare ( + segment_name.as_string ()) + == 0; + if (!name_matches) + continue; + + TyTy::BaseType *ty = nullptr; + if (!query_type (func->get_mappings ().get_hirid (), &ty)) + continue; + if (ty->get_kind () == TyTy::TypeKind::ERROR) + continue; + + rust_assert (ty->get_kind () == TyTy::TypeKind::FNDEF); + TyTy::FnType *fnty = static_cast<TyTy::FnType *> (ty); + const TyTy::BaseType *impl_self + = TypeCheckItem::ResolveImplBlockSelf (*impl); + + // see: + // https://gcc-rust.zulipchat.com/#narrow/stream/266897-general/topic/Method.20Resolution/near/338646280 + // https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/method/probe.rs#L650-L660 + bool impl_self_is_ptr + = impl_self->get_kind () == TyTy::TypeKind::POINTER; + bool impl_self_is_ref = impl_self->get_kind () == TyTy::TypeKind::REF; + if (receiver_is_raw_ptr && impl_self_is_ptr) + { + const TyTy::PointerType &sptr + = *static_cast<const TyTy::PointerType *> (impl_self); + const TyTy::PointerType &ptr + = *static_cast<const TyTy::PointerType *> (raw); + + // we could do this via lang-item assemblies if we refactor this + bool mut_match = sptr.mutability () == ptr.mutability (); + if (!mut_match) + continue; + } + else if (receiver_is_ref && impl_self_is_ref) + { + const TyTy::ReferenceType &sptr + = *static_cast<const TyTy::ReferenceType *> (impl_self); + const TyTy::ReferenceType &ptr + = *static_cast<const TyTy::ReferenceType *> (raw); + + // we could do this via lang-item assemblies if we refactor this + bool mut_match = sptr.mutability () == ptr.mutability (); + if (!mut_match) + continue; + } + + inherent_impl_fns.push_back ({func, impl, fnty}); + return true; + } - TraitReference *trait_ref - = TraitResolver::Resolve (*impl->get_trait_ref ().get ()); - rust_assert (!trait_ref->is_error ()); + TraitReference *trait_ref = TraitResolver::Resolve (impl->get_trait_ref ()); + rust_assert (!trait_ref->is_error ()); - auto item_ref - = trait_ref->lookup_trait_item (segment_name.as_string (), - TraitItemReference::TraitItemType::FN); - if (item_ref->is_error ()) - return true; + auto item_ref + = trait_ref->lookup_trait_item (segment_name.as_string (), + TraitItemReference::TraitItemType::FN); + if (item_ref->is_error ()) + return true; - const HIR::Trait *trait = trait_ref->get_hir_trait_ref (); - HIR::TraitItem *item = item_ref->get_hir_trait_item (); - if (item->get_item_kind () != HIR::TraitItem::TraitItemKind::FUNC) - return true; + const HIR::Trait *trait = trait_ref->get_hir_trait_ref (); + HIR::TraitItem *item = item_ref->get_hir_trait_item (); + if (item->get_item_kind () != HIR::TraitItem::TraitItemKind::FUNC) + return true; - HIR::TraitItemFunc *func = static_cast<HIR::TraitItemFunc *> (item); - if (!func->get_decl ().is_method ()) - return true; + HIR::TraitItemFunc *func = static_cast<HIR::TraitItemFunc *> (item); + if (!func->get_decl ().is_method ()) + return true; - TyTy::BaseType *ty = item_ref->get_tyty (); - rust_assert (ty->get_kind () == TyTy::TypeKind::FNDEF); - TyTy::FnType *fnty = static_cast<TyTy::FnType *> (ty); + TyTy::BaseType *ty = item_ref->get_tyty (); + rust_assert (ty->get_kind () == TyTy::TypeKind::FNDEF); + TyTy::FnType *fnty = static_cast<TyTy::FnType *> (ty); - trait_item_candidate candidate{func, trait, fnty, trait_ref, item_ref}; - trait_fns.push_back (candidate); + trait_item_candidate candidate{func, trait, fnty, trait_ref, item_ref}; + trait_fns.push_back (candidate); - return true; - }); + return true; + }); // lookup specified bounds for an associated item struct precdicate_candidate @@ -473,8 +472,11 @@ MethodResolver::get_predicate_items ( if (ty->get_kind () == TyTy::TypeKind::FNDEF) { TyTy::FnType *fnty = static_cast<TyTy::FnType *> (ty); - predicate_candidate candidate{lookup, fnty}; - predicate_items.push_back (candidate); + if (fnty->is_method ()) + { + predicate_candidate candidate{lookup, fnty}; + predicate_items.push_back (candidate); + } } } diff --git a/gcc/rust/typecheck/rust-hir-inherent-impl-overlap.h b/gcc/rust/typecheck/rust-hir-inherent-impl-overlap.h index 5cef1c2..5537b14 100644 --- a/gcc/rust/typecheck/rust-hir-inherent-impl-overlap.h +++ b/gcc/rust/typecheck/rust-hir-inherent-impl-overlap.h @@ -54,7 +54,7 @@ public: // impl-type -> [ (item, name), ... ] // } - HirId impl_type_id = impl->get_type ()->get_mappings ().get_hirid (); + HirId impl_type_id = impl->get_type ().get_mappings ().get_hirid (); TyTy::BaseType *impl_type = nullptr; bool ok = query_type (impl_type_id, &impl_type); if (!ok) diff --git a/gcc/rust/typecheck/rust-hir-path-probe.cc b/gcc/rust/typecheck/rust-hir-path-probe.cc index 196cc82..32e2399 100644 --- a/gcc/rust/typecheck/rust-hir-path-probe.cc +++ b/gcc/rust/typecheck/rust-hir-path-probe.cc @@ -168,7 +168,7 @@ PathProbeType::Probe (const TyTy::BaseType *receiver, if (!probe_bounds) return probe.candidates; - if (!probe.is_reciever_generic ()) + if (!probe.is_receiver_generic ()) { std::vector<std::pair<TraitReference *, HIR::ImplBlock *>> probed_bounds = TypeBoundsProbe::Probe (receiver); @@ -212,8 +212,8 @@ PathProbeType::visit (HIR::TypeAlias &alias) { HirId tyid = alias.get_mappings ().get_hirid (); TyTy::BaseType *ty = nullptr; - bool ok = query_type (tyid, &ty); - rust_assert (ok); + if (!query_type (tyid, &ty)) + return; PathProbeCandidate::ImplItemCandidate impl_item_candidate{&alias, current_impl}; @@ -232,8 +232,8 @@ PathProbeType::visit (HIR::ConstantItem &constant) { HirId tyid = constant.get_mappings ().get_hirid (); TyTy::BaseType *ty = nullptr; - bool ok = query_type (tyid, &ty); - rust_assert (ok); + if (!query_type (tyid, &ty)) + return; PathProbeCandidate::ImplItemCandidate impl_item_candidate{&constant, current_impl}; @@ -252,8 +252,8 @@ PathProbeType::visit (HIR::Function &function) { HirId tyid = function.get_mappings ().get_hirid (); TyTy::BaseType *ty = nullptr; - bool ok = query_type (tyid, &ty); - rust_assert (ok); + if (!query_type (tyid, &ty)) + return; PathProbeCandidate::ImplItemCandidate impl_item_candidate{&function, current_impl}; @@ -297,7 +297,7 @@ PathProbeType::process_impl_item_candidate (HirId id, HIR::ImplItem *item, HIR::ImplBlock *impl) { current_impl = impl; - HirId impl_ty_id = impl->get_type ()->get_mappings ().get_hirid (); + HirId impl_ty_id = impl->get_type ().get_mappings ().get_hirid (); TyTy::BaseType *impl_block_ty = nullptr; if (!query_type (impl_ty_id, &impl_block_ty)) return; @@ -346,7 +346,7 @@ PathProbeType::process_associated_trait_for_candidates ( const TyTy::TypeBoundPredicate p (*trait_ref, BoundPolarity::RegularBound, UNDEF_LOCATION); - TyTy::TypeBoundPredicateItem item (&p, trait_item_ref); + TyTy::TypeBoundPredicateItem item (p, trait_item_ref); TyTy::BaseType *trait_item_tyty = item.get_raw_item ()->get_tyty (); if (receiver->get_kind () != TyTy::DYNAMIC) @@ -433,7 +433,7 @@ PathProbeType::union_bounds ( } bool -PathProbeType::is_reciever_generic () const +PathProbeType::is_receiver_generic () const { const TyTy::BaseType *root = receiver->get_root (); bool receiver_is_type_param = root->get_kind () == TyTy::TypeKind::PARAM; @@ -472,8 +472,7 @@ PathProbeImplTrait::process_trait_impl_items_for_candidates () if (!impl->has_trait_ref ()) return true; - TraitReference *resolved - = TraitResolver::Lookup (*(impl->get_trait_ref ().get ())); + TraitReference *resolved = TraitResolver::Lookup (impl->get_trait_ref ()); if (!trait_reference->is_equal (*resolved)) return true; diff --git a/gcc/rust/typecheck/rust-hir-path-probe.h b/gcc/rust/typecheck/rust-hir-path-probe.h index 09a6492..59ffeb1 100644 --- a/gcc/rust/typecheck/rust-hir-path-probe.h +++ b/gcc/rust/typecheck/rust-hir-path-probe.h @@ -145,7 +145,7 @@ protected: const std::vector<std::pair<const TraitReference *, HIR::ImplBlock *>> b) const; - bool is_reciever_generic () const; + bool is_receiver_generic () const; const TyTy::BaseType *receiver; const HIR::PathIdentSegment &search; diff --git a/gcc/rust/typecheck/rust-hir-trait-reference.cc b/gcc/rust/typecheck/rust-hir-trait-reference.cc index 2ac086c..83985f0 100644 --- a/gcc/rust/typecheck/rust-hir-trait-reference.cc +++ b/gcc/rust/typecheck/rust-hir-trait-reference.cc @@ -106,7 +106,7 @@ TraitItemReference::get_error () const TraitReference::TraitReference ( const HIR::Trait *hir_trait_ref, std::vector<TraitItemReference> item_refs, - std::vector<const TraitReference *> super_traits, + std::vector<TyTy::TypeBoundPredicate> super_traits, std::vector<TyTy::SubstitutionParamMapping> substs) : hir_trait_ref (hir_trait_ref), item_refs (item_refs), super_traits (super_traits) @@ -263,7 +263,8 @@ TraitReference::lookup_hir_trait_item (const HIR::TraitItem &item, bool TraitReference::lookup_trait_item (const std::string &ident, - const TraitItemReference **ref) const + const TraitItemReference **ref, + bool lookup_supers) const { for (auto &item : item_refs) { @@ -274,10 +275,13 @@ TraitReference::lookup_trait_item (const std::string &ident, } } + if (!lookup_supers) + return false; + // lookup super traits for (const auto &super_trait : super_traits) { - bool found = super_trait->lookup_trait_item (ident, ref); + bool found = super_trait.get ()->lookup_trait_item (ident, ref); if (found) return true; } @@ -302,7 +306,7 @@ TraitReference::lookup_trait_item (const std::string &ident, for (const auto &super_trait : super_traits) { const TraitItemReference *res - = super_trait->lookup_trait_item (ident, type); + = super_trait.get ()->lookup_trait_item (ident, type); if (!res->is_error ()) return res; } @@ -330,7 +334,7 @@ TraitReference::get_trait_items_and_supers ( result.push_back (&item); for (const auto &super_trait : super_traits) - super_trait->get_trait_items_and_supers (result); + super_trait.get ()->get_trait_items_and_supers (result); } void @@ -374,7 +378,7 @@ TraitReference::is_equal (const TraitReference &other) const return this_id == other_id; } -const std::vector<const TraitReference *> +std::vector<TyTy::TypeBoundPredicate> TraitReference::get_super_traits () const { return super_traits; @@ -385,10 +389,10 @@ TraitReference::is_object_safe (bool emit_error, location_t locus) const { // https: // doc.rust-lang.org/reference/items/traits.html#object-safety std::vector<const TraitReference *> non_object_super_traits; - for (auto &item : super_traits) + for (auto &super_trait : super_traits) { - if (!item->is_object_safe (false, UNDEF_LOCATION)) - non_object_super_traits.push_back (item); + if (!super_trait.get ()->is_object_safe (false, UNDEF_LOCATION)) + non_object_super_traits.push_back (super_trait.get ()); } std::vector<const Resolver::TraitItemReference *> non_object_safe_items; @@ -434,7 +438,7 @@ TraitReference::satisfies_bound (const TraitReference &reference) const for (const auto &super_trait : super_traits) { - if (super_trait->satisfies_bound (reference)) + if (super_trait.get ()->satisfies_bound (reference)) return true; } diff --git a/gcc/rust/typecheck/rust-hir-trait-reference.h b/gcc/rust/typecheck/rust-hir-trait-reference.h index bdfd987..8b1ac7d 100644 --- a/gcc/rust/typecheck/rust-hir-trait-reference.h +++ b/gcc/rust/typecheck/rust-hir-trait-reference.h @@ -144,7 +144,7 @@ class TraitReference public: TraitReference (const HIR::Trait *hir_trait_ref, std::vector<TraitItemReference> item_refs, - std::vector<const TraitReference *> super_traits, + std::vector<TyTy::TypeBoundPredicate> super_traits, std::vector<TyTy::SubstitutionParamMapping> substs); TraitReference (TraitReference const &other); @@ -196,7 +196,8 @@ public: const TraitItemReference **ref) const; bool lookup_trait_item (const std::string &ident, - const TraitItemReference **ref) const; + const TraitItemReference **ref, + bool lookup_supers = true) const; const TraitItemReference * lookup_trait_item (const std::string &ident, @@ -217,7 +218,7 @@ public: bool is_equal (const TraitReference &other) const; - const std::vector<const TraitReference *> get_super_traits () const; + std::vector<TyTy::TypeBoundPredicate> get_super_traits () const; bool is_object_safe (bool emit_error, location_t locus) const; @@ -230,7 +231,7 @@ public: private: const HIR::Trait *hir_trait_ref; std::vector<TraitItemReference> item_refs; - std::vector<const TraitReference *> super_traits; + std::vector<TyTy::TypeBoundPredicate> super_traits; std::vector<TyTy::SubstitutionParamMapping> trait_substs; }; @@ -246,15 +247,16 @@ public: HIR::ImplBlock *get_impl_block (); + location_t get_locus () const; + TyTy::BaseType *get_self (); const TyTy::BaseType *get_self () const; void setup_raw_associated_types (); - TyTy::BaseType * - setup_associated_types (const TyTy::BaseType *self, - const TyTy::TypeBoundPredicate &bound, - TyTy::SubstitutionArgumentMappings *args = nullptr); + TyTy::BaseType *setup_associated_types ( + const TyTy::BaseType *self, const TyTy::TypeBoundPredicate &bound, + TyTy::SubstitutionArgumentMappings *args = nullptr, bool infer = true); void reset_associated_types (); diff --git a/gcc/rust/typecheck/rust-hir-trait-resolve.cc b/gcc/rust/typecheck/rust-hir-trait-resolve.cc index 51a6417..032bb58 100644 --- a/gcc/rust/typecheck/rust-hir-trait-resolve.cc +++ b/gcc/rust/typecheck/rust-hir-trait-resolve.cc @@ -20,6 +20,10 @@ #include "rust-hir-type-check-expr.h" #include "rust-substitution-mapper.h" #include "rust-type-util.h" +#include "rust-immutable-name-resolution-context.h" + +// used for flag_name_resolution_2_0 +#include "options.h" namespace Rust { namespace Resolver { @@ -65,7 +69,7 @@ ResolveTraitItemToRef::visit (HIR::TraitItemFunc &fn) { // create trait-item-ref location_t locus = fn.get_locus (); - bool is_optional = fn.has_block_defined (); + bool is_optional = fn.has_definition (); std::string identifier = fn.get_decl ().get_function_name ().as_string (); resolved = TraitItemReference (identifier, is_optional, @@ -103,6 +107,16 @@ TraitResolver::Lookup (HIR::TypePath &path) return resolver.lookup_path (path); } +HIR::Trait * +TraitResolver::ResolveHirItem (const HIR::TypePath &path) +{ + TraitResolver resolver; + + HIR::Trait *lookup = nullptr; + bool ok = resolver.resolve_path_to_trait (path, &lookup); + return ok ? lookup : nullptr; +} + TraitResolver::TraitResolver () : TypeCheckBase () {} bool @@ -110,26 +124,57 @@ TraitResolver::resolve_path_to_trait (const HIR::TypePath &path, HIR::Trait **resolved) const { NodeId ref; - if (!resolver->lookup_resolved_type (path.get_mappings ().get_nodeid (), - &ref)) + bool ok; + if (flag_name_resolution_2_0) + { + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); + + auto ref_opt = nr_ctx.lookup (path.get_mappings ().get_nodeid ()); + + if ((ok = ref_opt.has_value ())) + ref = *ref_opt; + } + else + { + auto path_nodeid = path.get_mappings ().get_nodeid (); + ok = resolver->lookup_resolved_type (path_nodeid, &ref) + || resolver->lookup_resolved_name (path_nodeid, &ref) + || resolver->lookup_resolved_macro (path_nodeid, &ref); + } + + if (!ok) { rust_error_at (path.get_locus (), "Failed to resolve path to node-id"); return false; } - if (auto hid = mappings.lookup_node_to_hir (ref)) + auto hid = mappings.lookup_node_to_hir (ref); + if (!hid) { - tl::optional<HIR::Item *> resolved_item - = mappings.lookup_hir_item (hid.value ()); - rust_assert (resolved_item.has_value ()); - rust_assert (resolved_item.value ()->get_item_kind () - == HIR::Item::ItemKind::Trait); - *resolved = static_cast<HIR::Trait *> (*resolved_item); + rust_error_at (path.get_locus (), "Failed to resolve path to hir-id"); + return false; + } - return true; + auto resolved_item = mappings.lookup_hir_item (hid.value ()); + if (!resolved_item.has_value ()) + { + rust_error_at (path.get_locus (), + "Failed to resolve trait by looking up hir node"); + return false; } - rust_error_at (path.get_locus (), "Failed to resolve path to hir-id"); - return false; + + if (resolved_item.value ()->get_item_kind () != HIR::Item::ItemKind::Trait) + { + rich_location r (line_table, path.get_locus ()); + r.add_fixit_replace ("not a trait"); + rust_error_at (r, ErrorCode::E0404, "Expected a trait found %qs", + path.as_simple_path ().as_string ().c_str ()); + return false; + } + + *resolved = static_cast<HIR::Trait *> (*resolved_item); + return true; } TraitReference * @@ -189,8 +234,9 @@ TraitResolver::resolve_trait (HIR::Trait *trait_reference) // The one exception is the implicit Self type of a trait bool apply_sized = !is_self; auto param_type - = TypeResolveGenericParam::Resolve (generic_param.get (), + = TypeResolveGenericParam::Resolve (*generic_param, true, apply_sized); + context->insert_type (generic_param->get_mappings (), param_type); substitutions.push_back ( TyTy::SubstitutionParamMapping (typaram, param_type)); @@ -228,7 +274,7 @@ TraitResolver::resolve_trait (HIR::Trait *trait_reference) specified_bounds.push_back (self_hrtb); // look for any - std::vector<const TraitReference *> super_traits; + std::vector<TyTy::TypeBoundPredicate> super_traits; if (trait_reference->has_type_param_bounds ()) { for (auto &bound : trait_reference->get_type_param_bounds ()) @@ -241,17 +287,18 @@ TraitResolver::resolve_trait (HIR::Trait *trait_reference) auto predicate = get_predicate_from_bound ( b->get_path (), - nullptr /*this will setup a PLACEHOLDER for self*/); + tl::nullopt /*this will setup a PLACEHOLDER for self*/); if (predicate.is_error ()) return &TraitReference::error_node (); specified_bounds.push_back (predicate); - super_traits.push_back (predicate.get ()); + super_traits.push_back (predicate); } } } self->inherit_bounds (specified_bounds); + context->block_context ().enter (TypeCheckBlockContextItem (trait_reference)); std::vector<TraitItemReference> item_refs; for (auto &item : trait_reference->get_trait_items ()) { @@ -266,8 +313,7 @@ TraitResolver::resolve_trait (HIR::Trait *trait_reference) item_refs.push_back (std::move (trait_item_ref)); } - TraitReference trait_object (trait_reference, item_refs, - std::move (super_traits), + TraitReference trait_object (trait_reference, item_refs, super_traits, std::move (substitutions)); context->insert_trait_reference ( trait_reference->get_mappings ().get_defid (), std::move (trait_object)); @@ -281,6 +327,7 @@ TraitResolver::resolve_trait (HIR::Trait *trait_reference) // resolve the blocks of functions etc because it can end up in a recursive // loop of trying to resolve traits as required by the types tref->on_resolved (); + context->block_context ().exit (); return tref; } @@ -329,6 +376,7 @@ TraitItemReference::resolve_item (HIR::TraitItemType &type) { TyTy::BaseType *ty = new TyTy::PlaceholderType (type.get_name ().as_string (), + type.get_mappings ().get_defid (), type.get_mappings ().get_hirid ()); context->insert_type (type.get_mappings (), ty); } @@ -336,7 +384,26 @@ TraitItemReference::resolve_item (HIR::TraitItemType &type) void TraitItemReference::resolve_item (HIR::TraitItemConst &constant) { - // TODO + TyTy::BaseType *ty = nullptr; + if (constant.has_type ()) + ty = TypeCheckType::Resolve (constant.get_type ()); + + TyTy::BaseType *expr = nullptr; + if (constant.has_expr ()) + expr = TypeCheckExpr::Resolve (constant.get_expr ()); + + bool have_specified_ty = ty != nullptr && !ty->is<TyTy::ErrorType> (); + bool have_expr_ty = expr != nullptr && !expr->is<TyTy::ErrorType> (); + + if (have_specified_ty && have_expr_ty) + { + coercion_site (constant.get_mappings ().get_hirid (), + TyTy::TyWithLocation (ty, + constant.get_type ().get_locus ()), + TyTy::TyWithLocation (expr, + constant.get_expr ().get_locus ()), + constant.get_locus ()); + } } void @@ -357,11 +424,11 @@ TraitItemReference::resolve_item (HIR::TraitItemFunc &func) auto expected_ret_tyty = resolved_fn_type->get_return_type (); context->push_return_type (TypeCheckContextItem (&func), expected_ret_tyty); - auto block_expr_ty = TypeCheckExpr::Resolve (func.get_block_expr ().get ()); + auto block_expr_ty = TypeCheckExpr::Resolve (func.get_block_expr ()); location_t fn_return_locus = func.get_decl ().has_return_type () - ? func.get_decl ().get_return_type ()->get_locus () + ? func.get_decl ().get_return_type ().get_locus () : func.get_locus (); coercion_site (func.get_mappings ().get_hirid (), @@ -445,7 +512,7 @@ AssociatedImplTrait::setup_raw_associated_types () TyTy::BaseType * AssociatedImplTrait::setup_associated_types ( const TyTy::BaseType *self, const TyTy::TypeBoundPredicate &bound, - TyTy::SubstitutionArgumentMappings *args) + TyTy::SubstitutionArgumentMappings *args, bool infer) { // compute the constrained impl block generic arguments based on self and the // higher ranked trait bound @@ -505,7 +572,7 @@ AssociatedImplTrait::setup_associated_types ( std::vector<TyTy::SubstitutionArg> subst_args; for (auto &p : substitutions) { - if (p.needs_substitution ()) + if (p.needs_substitution () && infer) { TyTy::TyVar infer_var = TyTy::TyVar::get_implicit_infer_var (locus); subst_args.push_back ( @@ -579,7 +646,7 @@ AssociatedImplTrait::setup_associated_types ( = unify_site_and (a->get_ref (), TyTy::TyWithLocation (a), TyTy::TyWithLocation (b), impl_predicate.get_locus (), true /*emit-errors*/, true /*commit-if-ok*/, - false /*infer*/, true /*cleanup-on-fail*/); + true /*infer*/, true /*cleanup-on-fail*/); rust_assert (result->get_kind () != TyTy::TypeKind::ERROR); } @@ -592,7 +659,7 @@ AssociatedImplTrait::setup_associated_types ( TyTy::TyWithLocation (impl_self_infer), impl_predicate.get_locus (), true /*emit-errors*/, true /*commit-if-ok*/, - false /*infer*/, true /*cleanup-on-fail*/); + true /*infer*/, true /*cleanup-on-fail*/); rust_assert (result->get_kind () != TyTy::TypeKind::ERROR); TyTy::BaseType *self_result = result; @@ -662,6 +729,12 @@ AssociatedImplTrait::reset_associated_types () trait->clear_associated_types (); } +location_t +AssociatedImplTrait::get_locus () const +{ + return impl->get_locus (); +} + Analysis::NodeMapping TraitItemReference::get_parent_trait_mappings () const { diff --git a/gcc/rust/typecheck/rust-hir-trait-resolve.h b/gcc/rust/typecheck/rust-hir-trait-resolve.h index 916abe6..b79fe17 100644 --- a/gcc/rust/typecheck/rust-hir-trait-resolve.h +++ b/gcc/rust/typecheck/rust-hir-trait-resolve.h @@ -58,6 +58,8 @@ public: static TraitReference *Lookup (HIR::TypePath &path); + static HIR::Trait *ResolveHirItem (const HIR::TypePath &path); + private: TraitResolver (); diff --git a/gcc/rust/typecheck/rust-hir-type-bounds.h b/gcc/rust/typecheck/rust-hir-type-bounds.h index 7fdba1c..82333f1 100644 --- a/gcc/rust/typecheck/rust-hir-type-bounds.h +++ b/gcc/rust/typecheck/rust-hir-type-bounds.h @@ -38,6 +38,7 @@ public: private: void scan (); void assemble_sized_builtin (); + void add_trait_bound (HIR::Trait *trait); void assemble_builtin_candidate (LangItem::Kind item); private: diff --git a/gcc/rust/typecheck/rust-hir-type-check-base.cc b/gcc/rust/typecheck/rust-hir-type-check-base.cc index 7e34cef..14b8ab8 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-base.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-base.cc @@ -31,6 +31,36 @@ TypeCheckBase::TypeCheckBase () context (TypeCheckContext::get ()) {} +void +TypeCheckBase::ResolveGenericParams ( + const std::vector<std::unique_ptr<HIR::GenericParam>> &generic_params, + std::vector<TyTy::SubstitutionParamMapping> &substitutions, bool is_foreign, + ABI abi) +{ + TypeCheckBase ctx; + ctx.resolve_generic_params (generic_params, substitutions, is_foreign, abi); +} + +static void +walk_types_to_constrain (std::set<HirId> &constrained_symbols, + const TyTy::SubstitutionArgumentMappings &constraints) +{ + for (const auto &c : constraints.get_mappings ()) + { + const TyTy::BaseType *arg = c.get_tyty (); + if (arg != nullptr) + { + const TyTy::BaseType *p = arg->get_root (); + constrained_symbols.insert (p->get_ty_ref ()); + if (p->has_substitutions_defined ()) + { + walk_types_to_constrain (constrained_symbols, + p->get_subst_argument_mappings ()); + } + } + } +} + bool TypeCheckBase::check_for_unconstrained ( const std::vector<TyTy::SubstitutionParamMapping> ¶ms_to_constrain, @@ -52,28 +82,14 @@ TypeCheckBase::check_for_unconstrained ( HirId ref = p.get_param_ty ()->get_ref (); symbols_to_constrain.insert (ref); symbol_to_location.insert ({ref, p.get_param_locus ()}); + + rust_debug_loc (p.get_param_locus (), "XX constrain THIS"); } // set up the set of constrained symbols std::set<HirId> constrained_symbols; - for (const auto &c : constraint_a.get_mappings ()) - { - const TyTy::BaseType *arg = c.get_tyty (); - if (arg != nullptr) - { - const TyTy::BaseType *p = arg->get_root (); - constrained_symbols.insert (p->get_ty_ref ()); - } - } - for (const auto &c : constraint_b.get_mappings ()) - { - const TyTy::BaseType *arg = c.get_tyty (); - if (arg != nullptr) - { - const TyTy::BaseType *p = arg->get_root (); - constrained_symbols.insert (p->get_ty_ref ()); - } - } + walk_types_to_constrain (constrained_symbols, constraint_a); + walk_types_to_constrain (constrained_symbols, constraint_b); const auto root = reference->get_root (); if (root->get_kind () == TyTy::TypeKind::PARAM) @@ -292,9 +308,20 @@ TypeCheckBase::parse_repr_options (const AST::AttrVec &attrs, location_t locus) repr.pack = 0; repr.align = 0; + // Default repr for enums is isize, but we now check for other repr in the + // attributes. + bool ok = context->lookup_builtin ("isize", &repr.repr); + rust_assert (ok); + for (const auto &attr : attrs) { bool is_repr = attr.get_path ().as_string () == Values::Attributes::REPR; + if (is_repr && !attr.has_attr_input ()) + { + rust_error_at (attr.get_locus (), "malformed %qs attribute", "repr"); + continue; + } + if (is_repr) { const AST::AttrInput &input = attr.get_attr_input (); @@ -305,21 +332,51 @@ TypeCheckBase::parse_repr_options (const AST::AttrVec &attrs, location_t locus) AST::AttrInputMetaItemContainer *meta_items = option.parse_to_meta_item (); - const std::string inline_option - = meta_items->get_items ().at (0)->as_string (); + if (meta_items == nullptr) + { + rust_error_at (attr.get_locus (), "malformed %qs attribute", + "repr"); + continue; + } + + auto &items = meta_items->get_items (); + if (items.size () == 0) + { + // nothing to do with this its empty + delete meta_items; + continue; + } + + const std::string inline_option = items.at (0)->as_string (); // TODO: it would probably be better to make the MetaItems more aware // of constructs with nesting like #[repr(packed(2))] rather than // manually parsing the string "packed(2)" here. size_t oparen = inline_option.find ('(', 0); - bool is_pack = false, is_align = false; + bool is_pack = false; + bool is_align = false; + bool is_c = false; + bool is_integer = false; unsigned char value = 1; if (oparen == std::string::npos) { is_pack = inline_option.compare ("packed") == 0; is_align = inline_option.compare ("align") == 0; + is_c = inline_option.compare ("C") == 0; + is_integer = (inline_option.compare ("isize") == 0 + || inline_option.compare ("i8") == 0 + || inline_option.compare ("i16") == 0 + || inline_option.compare ("i32") == 0 + || inline_option.compare ("i64") == 0 + || inline_option.compare ("i128") == 0 + || inline_option.compare ("usize") == 0 + || inline_option.compare ("u8") == 0 + || inline_option.compare ("u16") == 0 + || inline_option.compare ("u32") == 0 + || inline_option.compare ("u64") == 0 + || inline_option.compare ("u128") == 0); } else @@ -339,9 +396,30 @@ TypeCheckBase::parse_repr_options (const AST::AttrVec &attrs, location_t locus) } if (is_pack) - repr.pack = value; + { + repr.repr_kind = TyTy::ADTType::ReprKind::PACKED; + repr.pack = value; + } else if (is_align) - repr.align = value; + { + repr.repr_kind = TyTy::ADTType::ReprKind::ALIGN; + repr.align = value; + } + else if (is_c) + { + repr.repr_kind = TyTy::ADTType::ReprKind::C; + } + else if (is_integer) + { + repr.repr_kind = TyTy::ADTType::ReprKind::INT; + bool ok = context->lookup_builtin (inline_option, &repr.repr); + if (!ok) + { + rust_error_at (attr.get_locus (), "Invalid repr type"); + } + } + + delete meta_items; // Multiple repr options must be specified with e.g. #[repr(C, // packed(2))]. @@ -355,7 +433,8 @@ TypeCheckBase::parse_repr_options (const AST::AttrVec &attrs, location_t locus) void TypeCheckBase::resolve_generic_params ( const std::vector<std::unique_ptr<HIR::GenericParam>> &generic_params, - std::vector<TyTy::SubstitutionParamMapping> &substitutions) + std::vector<TyTy::SubstitutionParamMapping> &substitutions, bool is_foreign, + ABI abi) { for (auto &generic_param : generic_params) { @@ -365,31 +444,33 @@ TypeCheckBase::resolve_generic_params ( auto lifetime_param = static_cast<HIR::LifetimeParam &> (*generic_param); auto lifetime = lifetime_param.get_lifetime (); - rust_assert (lifetime.get_lifetime_type () - == AST::Lifetime::LifetimeType::NAMED); context->get_lifetime_resolver ().insert_mapping ( context->intern_lifetime (lifetime)); } - break; case HIR::GenericParam::GenericKind::CONST: { - auto param - = static_cast<HIR::ConstGenericParam *> (generic_param.get ()); - auto specified_type - = TypeCheckType::Resolve (param->get_type ().get ()); + if (is_foreign && abi != Rust::ABI::INTRINSIC) + { + rust_error_at (generic_param->get_locus (), ErrorCode::E0044, + "foreign items may not have const parameters"); + } + + auto ¶m + = static_cast<HIR::ConstGenericParam &> (*generic_param); + auto specified_type = TypeCheckType::Resolve (param.get_type ()); - if (param->has_default_expression ()) + if (param.has_default_expression ()) { - auto expr_type = TypeCheckExpr::Resolve ( - param->get_default_expression ().get ()); - - coercion_site ( - param->get_mappings ().get_hirid (), - TyTy::TyWithLocation (specified_type), - TyTy::TyWithLocation ( - expr_type, param->get_default_expression ()->get_locus ()), - param->get_locus ()); + auto expr_type + = TypeCheckExpr::Resolve (param.get_default_expression ()); + + coercion_site (param.get_mappings ().get_hirid (), + TyTy::TyWithLocation (specified_type), + TyTy::TyWithLocation ( + expr_type, + param.get_default_expression ().get_locus ()), + param.get_locus ()); } context->insert_type (generic_param->get_mappings (), @@ -398,16 +479,31 @@ TypeCheckBase::resolve_generic_params ( break; case HIR::GenericParam::GenericKind::TYPE: { - auto param_type - = TypeResolveGenericParam::Resolve (generic_param.get ()); + if (is_foreign && abi != Rust::ABI::INTRINSIC) + { + rust_error_at (generic_param->get_locus (), ErrorCode::E0044, + "foreign items may not have type parameters"); + } + + auto param_type = TypeResolveGenericParam::Resolve ( + *generic_param, false /*resolve_trait_bounds*/); context->insert_type (generic_param->get_mappings (), param_type); - substitutions.push_back (TyTy::SubstitutionParamMapping ( - static_cast<HIR::TypeParam &> (*generic_param), param_type)); + auto ¶m = static_cast<HIR::TypeParam &> (*generic_param); + TyTy::SubstitutionParamMapping p (param, param_type); + substitutions.push_back (p); } break; } } + + // now walk them to setup any specified type param bounds + for (auto &subst : substitutions) + { + auto pty = subst.get_param_ty (); + TypeResolveGenericParam::ApplyAnyTraitBounds (subst.get_generic_param (), + pty); + } } TyTy::TypeBoundPredicate diff --git a/gcc/rust/typecheck/rust-hir-type-check-base.h b/gcc/rust/typecheck/rust-hir-type-check-base.h index 0bc2905..580082a 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-base.h +++ b/gcc/rust/typecheck/rust-hir-type-check-base.h @@ -32,15 +32,21 @@ class TypeCheckBase public: virtual ~TypeCheckBase () {} + static void ResolveGenericParams ( + const std::vector<std::unique_ptr<HIR::GenericParam>> &generic_params, + std::vector<TyTy::SubstitutionParamMapping> &substitutions, bool is_foreign, + ABI abi); + protected: TypeCheckBase (); TraitReference *resolve_trait_path (HIR::TypePath &); - TyTy::TypeBoundPredicate - get_predicate_from_bound (HIR::TypePath &path, HIR::Type *associated_self, - BoundPolarity polarity - = BoundPolarity::RegularBound); + TyTy::TypeBoundPredicate get_predicate_from_bound ( + HIR::TypePath &path, + tl::optional<std::reference_wrapper<HIR::Type>> associated_self, + BoundPolarity polarity = BoundPolarity::RegularBound, + bool is_qualified_type = false); bool check_for_unconstrained ( const std::vector<TyTy::SubstitutionParamMapping> ¶ms_to_constrain, @@ -55,8 +61,9 @@ protected: location_t locus); void resolve_generic_params ( - const std::vector<std::unique_ptr<HIR::GenericParam> > &generic_params, - std::vector<TyTy::SubstitutionParamMapping> &substitutions); + const std::vector<std::unique_ptr<HIR::GenericParam>> &generic_params, + std::vector<TyTy::SubstitutionParamMapping> &substitutions, + bool is_foreign = false, ABI abi = ABI::RUST); TyTy::TypeBoundPredicate get_marker_predicate (LangItem::Kind item_type, location_t locus); diff --git a/gcc/rust/typecheck/rust-hir-type-check-enumitem.cc b/gcc/rust/typecheck/rust-hir-type-check-enumitem.cc index 72d8791..c80a12f 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-enumitem.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-enumitem.cc @@ -16,34 +16,39 @@ // along with GCC; see the file COPYING3. If not see // <http://www.gnu.org/licenses/>. +#include "rust-hir-expr.h" #include "rust-hir-type-check-type.h" #include "rust-hir-type-check-expr.h" #include "rust-hir-type-check-enumitem.h" #include "rust-type-util.h" +#include "rust-immutable-name-resolution-context.h" + +// for flag_name_resolution_2_0 +#include "options.h" namespace Rust { namespace Resolver { TyTy::VariantDef * -TypeCheckEnumItem::Resolve (HIR::EnumItem *item, int64_t last_discriminant) +TypeCheckEnumItem::Resolve (HIR::EnumItem &item, int64_t last_discriminant) { TypeCheckEnumItem resolver (last_discriminant); - switch (item->get_enum_item_kind ()) + switch (item.get_enum_item_kind ()) { case HIR::EnumItem::EnumItemKind::Named: - resolver.visit (static_cast<HIR::EnumItem &> (*item)); + resolver.visit (static_cast<HIR::EnumItem &> (item)); break; case HIR::EnumItem::EnumItemKind::Tuple: - resolver.visit (static_cast<HIR::EnumItemTuple &> (*item)); + resolver.visit (static_cast<HIR::EnumItemTuple &> (item)); break; case HIR::EnumItem::EnumItemKind::Struct: - resolver.visit (static_cast<HIR::EnumItemStruct &> (*item)); + resolver.visit (static_cast<HIR::EnumItemStruct &> (item)); break; case HIR::EnumItem::EnumItemKind::Discriminant: - resolver.visit (static_cast<HIR::EnumItemDiscriminant &> (*item)); + resolver.visit (static_cast<HIR::EnumItemDiscriminant &> (item)); break; } return resolver.variant; @@ -64,25 +69,39 @@ TypeCheckEnumItem::visit (HIR::EnumItem &item) mappings.get_next_hir_id ( item.get_mappings ().get_crate_num ()), item.get_mappings ().get_local_defid ()); - HIR::LiteralExpr *discim_expr - = new HIR::LiteralExpr (mapping, std::to_string (last_discriminant), - HIR::Literal::LitType::INT, - PrimitiveCoreType::CORETYPE_I64, item.get_locus (), - {}); + auto discim_expr = std::make_unique<HIR::LiteralExpr> ( + HIR::LiteralExpr (mapping, std::to_string (last_discriminant), + HIR::Literal::LitType::INT, + PrimitiveCoreType::CORETYPE_I64, item.get_locus (), {})); TyTy::BaseType *isize = nullptr; bool ok = context->lookup_builtin ("isize", &isize); rust_assert (ok); context->insert_type (mapping, isize); - auto canonical_path - = mappings.lookup_canonical_path (item.get_mappings ().get_nodeid ()); + tl::optional<CanonicalPath> canonical_path; + + if (flag_name_resolution_2_0) + { + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); + + canonical_path + = nr_ctx.types.to_canonical_path (item.get_mappings ().get_nodeid ()); + } + else + { + canonical_path + = mappings.lookup_canonical_path (item.get_mappings ().get_nodeid ()); + } + + rust_assert (canonical_path.has_value ()); RustIdent ident{*canonical_path, item.get_locus ()}; variant = new TyTy::VariantDef (item.get_mappings ().get_hirid (), item.get_mappings ().get_defid (), item.get_identifier ().as_string (), ident, - discim_expr); + std::move (discim_expr)); } void @@ -92,26 +111,42 @@ TypeCheckEnumItem::visit (HIR::EnumItemDiscriminant &item) rust_error_at (item.get_locus (), "discriminant too big"); auto &discriminant = item.get_discriminant_expression (); - auto capacity_type = TypeCheckExpr::Resolve (discriminant.get ()); + auto capacity_type = TypeCheckExpr::Resolve (discriminant); if (capacity_type->get_kind () == TyTy::TypeKind::ERROR) return; TyTy::ISizeType *expected_ty - = new TyTy::ISizeType (discriminant->get_mappings ().get_hirid ()); - context->insert_type (discriminant->get_mappings (), expected_ty); + = new TyTy::ISizeType (discriminant.get_mappings ().get_hirid ()); + context->insert_type (discriminant.get_mappings (), expected_ty); unify_site (item.get_mappings ().get_hirid (), TyTy::TyWithLocation (expected_ty), TyTy::TyWithLocation (capacity_type), item.get_locus ()); - auto canonical_path - = mappings.lookup_canonical_path (item.get_mappings ().get_nodeid ()); + tl::optional<CanonicalPath> canonical_path; + + if (flag_name_resolution_2_0) + { + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); + + canonical_path + = nr_ctx.types.to_canonical_path (item.get_mappings ().get_nodeid ()); + } + else + { + canonical_path + = mappings.lookup_canonical_path (item.get_mappings ().get_nodeid ()); + } + + rust_assert (canonical_path.has_value ()); RustIdent ident{*canonical_path, item.get_locus ()}; - variant = new TyTy::VariantDef (item.get_mappings ().get_hirid (), - item.get_mappings ().get_defid (), - item.get_identifier ().as_string (), ident, - item.get_discriminant_expression ().get ()); + variant + = new TyTy::VariantDef (item.get_mappings ().get_hirid (), + item.get_mappings ().get_defid (), + item.get_identifier ().as_string (), ident, + item.get_discriminant_expression ().clone_expr ()); } void @@ -125,7 +160,7 @@ TypeCheckEnumItem::visit (HIR::EnumItemTuple &item) for (auto &field : item.get_tuple_fields ()) { TyTy::BaseType *field_type - = TypeCheckType::Resolve (field.get_field_type ().get ()); + = TypeCheckType::Resolve (field.get_field_type ()); TyTy::StructFieldType *ty_field = new TyTy::StructFieldType (field.get_mappings ().get_hirid (), std::to_string (idx), field_type, @@ -140,26 +175,40 @@ TypeCheckEnumItem::visit (HIR::EnumItemTuple &item) mappings.get_next_hir_id ( item.get_mappings ().get_crate_num ()), item.get_mappings ().get_local_defid ()); - HIR::LiteralExpr *discim_expr - = new HIR::LiteralExpr (mapping, std::to_string (last_discriminant), - HIR::Literal::LitType::INT, - PrimitiveCoreType::CORETYPE_I64, item.get_locus (), - {}); + auto discim_expr = std::make_unique<HIR::LiteralExpr> ( + HIR::LiteralExpr (mapping, std::to_string (last_discriminant), + HIR::Literal::LitType::INT, + PrimitiveCoreType::CORETYPE_I64, item.get_locus (), {})); TyTy::BaseType *isize = nullptr; bool ok = context->lookup_builtin ("isize", &isize); rust_assert (ok); context->insert_type (mapping, isize); - auto canonical_path - = mappings.lookup_canonical_path (item.get_mappings ().get_nodeid ()); + tl::optional<CanonicalPath> canonical_path; + + if (flag_name_resolution_2_0) + { + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); + + canonical_path + = nr_ctx.types.to_canonical_path (item.get_mappings ().get_nodeid ()); + } + else + { + canonical_path + = mappings.lookup_canonical_path (item.get_mappings ().get_nodeid ()); + } + + rust_assert (canonical_path.has_value ()); RustIdent ident{*canonical_path, item.get_locus ()}; variant = new TyTy::VariantDef (item.get_mappings ().get_hirid (), item.get_mappings ().get_defid (), item.get_identifier ().as_string (), ident, TyTy::VariantDef::VariantType::TUPLE, - discim_expr, fields); + std::move (discim_expr), fields); } void @@ -172,7 +221,7 @@ TypeCheckEnumItem::visit (HIR::EnumItemStruct &item) for (auto &field : item.get_struct_fields ()) { TyTy::BaseType *field_type - = TypeCheckType::Resolve (field.get_field_type ().get ()); + = TypeCheckType::Resolve (field.get_field_type ()); TyTy::StructFieldType *ty_field = new TyTy::StructFieldType (field.get_mappings ().get_hirid (), field.get_field_name ().as_string (), @@ -186,26 +235,40 @@ TypeCheckEnumItem::visit (HIR::EnumItemStruct &item) mappings.get_next_hir_id ( item.get_mappings ().get_crate_num ()), item.get_mappings ().get_local_defid ()); - HIR::LiteralExpr *discrim_expr - = new HIR::LiteralExpr (mapping, std::to_string (last_discriminant), - HIR::Literal::LitType::INT, - PrimitiveCoreType::CORETYPE_I64, item.get_locus (), - {}); + auto discrim_expr = std::make_unique<HIR::LiteralExpr> ( + HIR::LiteralExpr (mapping, std::to_string (last_discriminant), + HIR::Literal::LitType::INT, + PrimitiveCoreType::CORETYPE_I64, item.get_locus (), {})); TyTy::BaseType *isize = nullptr; bool ok = context->lookup_builtin ("isize", &isize); rust_assert (ok); context->insert_type (mapping, isize); - auto canonical_path - = mappings.lookup_canonical_path (item.get_mappings ().get_nodeid ()); + tl::optional<CanonicalPath> canonical_path; + + if (flag_name_resolution_2_0) + { + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); + + canonical_path + = nr_ctx.types.to_canonical_path (item.get_mappings ().get_nodeid ()); + } + else + { + canonical_path + = mappings.lookup_canonical_path (item.get_mappings ().get_nodeid ()); + } + + rust_assert (canonical_path.has_value ()); RustIdent ident{*canonical_path, item.get_locus ()}; variant = new TyTy::VariantDef (item.get_mappings ().get_hirid (), item.get_mappings ().get_defid (), item.get_identifier ().as_string (), ident, TyTy::VariantDef::VariantType::STRUCT, - discrim_expr, fields); + std::move (discrim_expr), fields); } } // namespace Resolver diff --git a/gcc/rust/typecheck/rust-hir-type-check-enumitem.h b/gcc/rust/typecheck/rust-hir-type-check-enumitem.h index bccffe7..6b01a49 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-enumitem.h +++ b/gcc/rust/typecheck/rust-hir-type-check-enumitem.h @@ -28,7 +28,7 @@ namespace Resolver { class TypeCheckEnumItem : public TypeCheckBase { public: - static TyTy::VariantDef *Resolve (HIR::EnumItem *item, + static TyTy::VariantDef *Resolve (HIR::EnumItem &item, int64_t last_discriminant); protected: diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.cc b/gcc/rust/typecheck/rust-hir-type-check-expr.cc index 0e897813..cbf529a 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-expr.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-expr.cc @@ -16,6 +16,9 @@ // along with GCC; see the file COPYING3. If not see // <http://www.gnu.org/licenses/>. +#include "optional.h" +#include "rust-hir-expr.h" +#include "rust-system.h" #include "rust-tyty-call.h" #include "rust-hir-type-check-struct-field.h" #include "rust-hir-path-probe.h" @@ -27,6 +30,10 @@ #include "rust-hir-type-check-stmt.h" #include "rust-hir-type-check-item.h" #include "rust-type-util.h" +#include "rust-immutable-name-resolution-context.h" + +// for flag_name_resolution_2_0 +#include "options.h" namespace Rust { namespace Resolver { @@ -36,17 +43,17 @@ TypeCheckExpr::TypeCheckExpr () : TypeCheckBase (), infered (nullptr) {} // Perform type checking on expr. Also runs type unification algorithm. // Returns the unified type of expr TyTy::BaseType * -TypeCheckExpr::Resolve (HIR::Expr *expr) +TypeCheckExpr::Resolve (HIR::Expr &expr) { TypeCheckExpr resolver; - expr->accept_vis (resolver); + expr.accept_vis (resolver); if (resolver.infered == nullptr) - return new TyTy::ErrorType (expr->get_mappings ().get_hirid ()); + return new TyTy::ErrorType (expr.get_mappings ().get_hirid ()); - auto ref = expr->get_mappings ().get_hirid (); + auto ref = expr.get_mappings ().get_hirid (); resolver.infered->set_ref (ref); - resolver.context->insert_type (expr->get_mappings (), resolver.infered); + resolver.context->insert_type (expr.get_mappings (), resolver.infered); return resolver.infered; } @@ -54,10 +61,10 @@ TypeCheckExpr::Resolve (HIR::Expr *expr) void TypeCheckExpr::visit (HIR::TupleIndexExpr &expr) { - auto resolved = TypeCheckExpr::Resolve (expr.get_tuple_expr ().get ()); + auto resolved = TypeCheckExpr::Resolve (expr.get_tuple_expr ()); if (resolved->get_kind () == TyTy::TypeKind::ERROR) { - rust_error_at (expr.get_tuple_expr ()->get_locus (), + rust_error_at (expr.get_tuple_expr ().get_locus (), "failed to resolve TupleIndexExpr receiver"); return; } @@ -73,7 +80,7 @@ TypeCheckExpr::visit (HIR::TupleIndexExpr &expr) || resolved->get_kind () == TyTy::TypeKind::TUPLE; if (!is_valid_type) { - rust_error_at (expr.get_tuple_expr ()->get_locus (), + rust_error_at (expr.get_tuple_expr ().get_locus (), "Expected Tuple or ADT got: %s", resolved->as_string ().c_str ()); return; @@ -85,7 +92,9 @@ TypeCheckExpr::visit (HIR::TupleIndexExpr &expr) TupleIndex index = expr.get_tuple_index (); if ((size_t) index >= tuple->num_fields ()) { - rust_error_at (expr.get_locus (), "unknown field at index %i", index); + rust_error_at (expr.get_locus (), ErrorCode::E0609, + "no field %qi on type %qs", index, + resolved->get_name ().c_str ()); return; } @@ -129,19 +138,14 @@ TypeCheckExpr::visit (HIR::TupleExpr &expr) { if (expr.is_unit ()) { - auto unit_node_id = resolver->get_unit_type_node_id (); - if (!context->lookup_builtin (unit_node_id, &infered)) - { - rust_error_at (expr.get_locus (), - "failed to lookup builtin unit type"); - } + infered = TyTy::TupleType::get_unit_type (); return; } std::vector<TyTy::TyVar> fields; for (auto &elem : expr.get_tuple_elems ()) { - auto field_ty = TypeCheckExpr::Resolve (elem.get ()); + auto field_ty = TypeCheckExpr::Resolve (*elem); fields.push_back (TyTy::TyVar (field_ty->get_ref ())); } infered = new TyTy::TupleType (expr.get_mappings ().get_hirid (), @@ -161,12 +165,12 @@ TypeCheckExpr::visit (HIR::ReturnExpr &expr) auto fn_return_tyty = context->peek_return_type (); location_t expr_locus = expr.has_return_expr () - ? expr.get_expr ()->get_locus () + ? expr.get_expr ().get_locus () : expr.get_locus (); - TyTy::BaseType *expr_ty - = expr.has_return_expr () - ? TypeCheckExpr::Resolve (expr.get_expr ().get ()) - : TyTy::TupleType::get_unit_type (expr.get_mappings ().get_hirid ()); + + TyTy::BaseType *expr_ty = expr.has_return_expr () + ? TypeCheckExpr::Resolve (expr.get_expr ()) + : TyTy::TupleType::get_unit_type (); coercion_site (expr.get_mappings ().get_hirid (), TyTy::TyWithLocation (fn_return_tyty), @@ -178,8 +182,7 @@ TypeCheckExpr::visit (HIR::ReturnExpr &expr) void TypeCheckExpr::visit (HIR::CallExpr &expr) { - TyTy::BaseType *function_tyty - = TypeCheckExpr::Resolve (expr.get_fnexpr ().get ()); + TyTy::BaseType *function_tyty = TypeCheckExpr::Resolve (expr.get_fnexpr ()); rust_debug_loc (expr.get_locus (), "resolved_call_expr to: {%s}", function_tyty->get_name ().c_str ()); @@ -193,7 +196,7 @@ TypeCheckExpr::visit (HIR::CallExpr &expr) // lookup variant id HirId variant_id; bool ok = context->lookup_variant_definition ( - expr.get_fnexpr ()->get_mappings ().get_hirid (), &variant_id); + expr.get_fnexpr ().get_mappings ().get_hirid (), &variant_id); if (!ok) { @@ -207,14 +210,13 @@ TypeCheckExpr::visit (HIR::CallExpr &expr) ok = adt->lookup_variant_by_id (variant_id, &lookup_variant); rust_assert (ok); - variant = *lookup_variant; + variant = std::move (*lookup_variant->clone ()); } else { rust_assert (adt->number_of_variants () == 1); - variant = *adt->get_variants ().at (0); + variant = std::move (*adt->get_variants ().at (0)->clone ()); } - infered = TyTy::TypeCheckCallExpr::go (function_tyty, expr, variant, context); return; @@ -225,45 +227,96 @@ TypeCheckExpr::visit (HIR::CallExpr &expr) if (resolved_fn_trait_call) return; - bool valid_tyty = function_tyty->get_kind () == TyTy::TypeKind::FNDEF - || function_tyty->get_kind () == TyTy::TypeKind::FNPTR; + bool valid_tyty + = function_tyty->is<TyTy::FnType> () || function_tyty->is<TyTy::FnPtr> (); if (!valid_tyty) { - rust_error_at (expr.get_locus (), - "Failed to resolve expression of function call"); + bool emit_error = !function_tyty->is<TyTy::ErrorType> (); + if (emit_error) + { + rich_location r (line_table, expr.get_locus ()); + rust_error_at (r, ErrorCode::E0618, "expected function, found %<%s%>", + function_tyty->get_name ().c_str ()); + } return; } infered = TyTy::TypeCheckCallExpr::go (function_tyty, expr, variant, context); + + auto discriminant_type_lookup + = mappings.lookup_lang_item (LangItem::Kind::DISCRIMINANT_TYPE); + if (infered->is<TyTy::PlaceholderType> () && discriminant_type_lookup) + { + const auto &p = *static_cast<const TyTy::PlaceholderType *> (infered); + if (p.get_def_id () == discriminant_type_lookup.value ()) + { + // this is a special case where this will actually return the repr of + // the enum. We dont currently support repr on enum yet to change the + // discriminant type but the default is always isize. We need to + // assert this is a generic function with one param + // + // fn<BookFormat> (v & T=BookFormat{Paperback) -> <placeholder:> + // + // note the default is isize + + bool ok = context->lookup_builtin ("isize", &infered); + rust_assert (ok); + + rust_assert (function_tyty->is<TyTy::FnType> ()); + auto &fn = *static_cast<TyTy::FnType *> (function_tyty); + rust_assert (fn.has_substitutions ()); + rust_assert (fn.get_num_type_params () == 1); + auto &mapping = fn.get_substs ().at (0); + auto param_ty = mapping.get_param_ty (); + + if (!param_ty->can_resolve ()) + { + // this could be a valid error need to test more weird cases and + // look at rustc + rust_internal_error_at (expr.get_locus (), + "something wrong computing return type"); + return; + } + + auto resolved = param_ty->resolve (); + bool is_adt = resolved->is<TyTy::ADTType> (); + if (is_adt) + { + const auto &adt = *static_cast<TyTy::ADTType *> (resolved); + infered = adt.get_repr_options ().repr; + rust_assert (infered != nullptr); + } + } + } } void TypeCheckExpr::visit (HIR::AssignmentExpr &expr) { - infered = TyTy::TupleType::get_unit_type (expr.get_mappings ().get_hirid ()); + infered = TyTy::TupleType::get_unit_type (); - auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ().get ()); - auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ().get ()); + auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ()); + auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ()); coercion_site (expr.get_mappings ().get_hirid (), - TyTy::TyWithLocation (lhs, expr.get_lhs ()->get_locus ()), - TyTy::TyWithLocation (rhs, expr.get_rhs ()->get_locus ()), + TyTy::TyWithLocation (lhs, expr.get_lhs ().get_locus ()), + TyTy::TyWithLocation (rhs, expr.get_rhs ().get_locus ()), expr.get_locus ()); } void TypeCheckExpr::visit (HIR::CompoundAssignmentExpr &expr) { - infered = TyTy::TupleType::get_unit_type (expr.get_mappings ().get_hirid ()); + infered = TyTy::TupleType::get_unit_type (); - auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ().get ()); - auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ().get ()); + auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ()); + auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ()); // we dont care about the result of the unify from a compound assignment // since this is a unit-type expr coercion_site (expr.get_mappings ().get_hirid (), - TyTy::TyWithLocation (lhs, expr.get_lhs ()->get_locus ()), - TyTy::TyWithLocation (rhs, expr.get_rhs ()->get_locus ()), + TyTy::TyWithLocation (lhs, expr.get_lhs ().get_locus ()), + TyTy::TyWithLocation (rhs, expr.get_rhs ().get_locus ()), expr.get_locus ()); auto lang_item_type @@ -296,8 +349,8 @@ TypeCheckExpr::visit (HIR::LiteralExpr &expr) void TypeCheckExpr::visit (HIR::ArithmeticOrLogicalExpr &expr) { - auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ().get ()); - auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ().get ()); + auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ()); + auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ()); auto lang_item_type = LangItem::OperatorToLangItem (expr.get_expr_type ()); bool operator_overloaded @@ -321,8 +374,8 @@ TypeCheckExpr::visit (HIR::ArithmeticOrLogicalExpr &expr) { case ArithmeticOrLogicalOperator::LEFT_SHIFT: case ArithmeticOrLogicalOperator::RIGHT_SHIFT: { - TyTy::TyWithLocation from (rhs, expr.get_rhs ()->get_locus ()); - TyTy::TyWithLocation to (lhs, expr.get_lhs ()->get_locus ()); + TyTy::TyWithLocation from (rhs, expr.get_rhs ().get_locus ()); + TyTy::TyWithLocation to (lhs, expr.get_lhs ().get_locus ()); infered = cast_site (expr.get_mappings ().get_hirid (), from, to, expr.get_locus ()); } @@ -331,8 +384,8 @@ TypeCheckExpr::visit (HIR::ArithmeticOrLogicalExpr &expr) default: { infered = unify_site ( expr.get_mappings ().get_hirid (), - TyTy::TyWithLocation (lhs, expr.get_lhs ()->get_locus ()), - TyTy::TyWithLocation (rhs, expr.get_rhs ()->get_locus ()), + TyTy::TyWithLocation (lhs, expr.get_lhs ().get_locus ()), + TyTy::TyWithLocation (rhs, expr.get_rhs ().get_locus ()), expr.get_locus ()); } break; @@ -342,12 +395,27 @@ TypeCheckExpr::visit (HIR::ArithmeticOrLogicalExpr &expr) void TypeCheckExpr::visit (HIR::ComparisonExpr &expr) { - auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ().get ()); - auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ().get ()); + auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ()); + auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ()); + + auto borrowed_rhs + = new TyTy::ReferenceType (mappings.get_next_hir_id (), + TyTy::TyVar (rhs->get_ref ()), Mutability::Imm); + context->insert_implicit_type (borrowed_rhs->get_ref (), borrowed_rhs); + + auto seg_name = LangItem::ComparisonToSegment (expr.get_expr_type ()); + auto segment = HIR::PathIdentSegment (seg_name); + auto lang_item_type = LangItem::ComparisonToLangItem (expr.get_expr_type ()); + + bool operator_overloaded + = resolve_operator_overload (lang_item_type, expr, lhs, borrowed_rhs, + segment); + if (operator_overloaded) + return; unify_site (expr.get_mappings ().get_hirid (), - TyTy::TyWithLocation (lhs, expr.get_lhs ()->get_locus ()), - TyTy::TyWithLocation (rhs, expr.get_rhs ()->get_locus ()), + TyTy::TyWithLocation (lhs, expr.get_lhs ().get_locus ()), + TyTy::TyWithLocation (rhs, expr.get_rhs ().get_locus ()), expr.get_locus ()); bool ok = context->lookup_builtin ("bool", &infered); @@ -357,8 +425,8 @@ TypeCheckExpr::visit (HIR::ComparisonExpr &expr) void TypeCheckExpr::visit (HIR::LazyBooleanExpr &expr) { - auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ().get ()); - auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ().get ()); + auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ()); + auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ()); // we expect the lhs and rhs must be bools at this point TyTy::BaseType *boolean_node = nullptr; @@ -368,27 +436,27 @@ TypeCheckExpr::visit (HIR::LazyBooleanExpr &expr) // verify the lhs and rhs before unifying together lhs = unify_site (expr.get_mappings ().get_hirid (), TyTy::TyWithLocation (boolean_node, - expr.get_lhs ()->get_locus ()), - TyTy::TyWithLocation (lhs, expr.get_lhs ()->get_locus ()), + expr.get_lhs ().get_locus ()), + TyTy::TyWithLocation (lhs, expr.get_lhs ().get_locus ()), expr.get_locus ()); rhs = unify_site (expr.get_mappings ().get_hirid (), TyTy::TyWithLocation (boolean_node, - expr.get_rhs ()->get_locus ()), - TyTy::TyWithLocation (rhs, expr.get_rhs ()->get_locus ()), + expr.get_rhs ().get_locus ()), + TyTy::TyWithLocation (rhs, expr.get_rhs ().get_locus ()), expr.get_locus ()); infered = unify_site (expr.get_mappings ().get_hirid (), - TyTy::TyWithLocation (lhs, expr.get_lhs ()->get_locus ()), - TyTy::TyWithLocation (rhs, expr.get_rhs ()->get_locus ()), + TyTy::TyWithLocation (lhs, expr.get_lhs ().get_locus ()), + TyTy::TyWithLocation (rhs, expr.get_rhs ().get_locus ()), expr.get_locus ()); } void TypeCheckExpr::visit (HIR::NegationExpr &expr) { - auto negated_expr_ty = TypeCheckExpr::Resolve (expr.get_expr ().get ()); + auto negated_expr_ty = TypeCheckExpr::Resolve (expr.get_expr ()); // check for operator overload auto lang_item_type @@ -453,17 +521,25 @@ TypeCheckExpr::visit (HIR::IfExpr &expr) bool ok = context->lookup_builtin ("bool", &bool_ty); rust_assert (ok); - TyTy::BaseType *cond_type - = TypeCheckExpr::Resolve (expr.get_if_condition ().get ()); + TyTy::BaseType *cond_type = TypeCheckExpr::Resolve (expr.get_if_condition ()); unify_site (expr.get_mappings ().get_hirid (), TyTy::TyWithLocation (bool_ty), TyTy::TyWithLocation (cond_type, - expr.get_if_condition ()->get_locus ()), + expr.get_if_condition ().get_locus ()), expr.get_locus ()); - TypeCheckExpr::Resolve (expr.get_if_block ().get ()); + TyTy::BaseType *block_type = TypeCheckExpr::Resolve (expr.get_if_block ()); - infered = TyTy::TupleType::get_unit_type (expr.get_mappings ().get_hirid ()); + TyTy::BaseType *unit_ty = nullptr; + ok = context->lookup_builtin ("()", &unit_ty); + rust_assert (ok); + + infered + = coercion_site (expr.get_mappings ().get_hirid (), + TyTy::TyWithLocation (unit_ty), + TyTy::TyWithLocation (block_type, + expr.get_if_block ().get_locus ()), + expr.get_locus ()); } void @@ -473,17 +549,15 @@ TypeCheckExpr::visit (HIR::IfExprConseqElse &expr) bool ok = context->lookup_builtin ("bool", &bool_ty); rust_assert (ok); - TyTy::BaseType *cond_type - = TypeCheckExpr::Resolve (expr.get_if_condition ().get ()); + TyTy::BaseType *cond_type = TypeCheckExpr::Resolve (expr.get_if_condition ()); unify_site (expr.get_mappings ().get_hirid (), TyTy::TyWithLocation (bool_ty), TyTy::TyWithLocation (cond_type, - expr.get_if_condition ()->get_locus ()), + expr.get_if_condition ().get_locus ()), expr.get_locus ()); - auto if_blk_resolved = TypeCheckExpr::Resolve (expr.get_if_block ().get ()); - auto else_blk_resolved - = TypeCheckExpr::Resolve (expr.get_else_block ().get ()); + auto if_blk_resolved = TypeCheckExpr::Resolve (expr.get_if_block ()); + auto else_blk_resolved = TypeCheckExpr::Resolve (expr.get_else_block ()); if (if_blk_resolved->get_kind () == TyTy::NEVER) infered = else_blk_resolved; @@ -491,81 +565,20 @@ TypeCheckExpr::visit (HIR::IfExprConseqElse &expr) infered = if_blk_resolved; else { - infered = unify_site ( - expr.get_mappings ().get_hirid (), - TyTy::TyWithLocation (if_blk_resolved, - expr.get_if_block ()->get_locus ()), - TyTy::TyWithLocation (else_blk_resolved, - expr.get_else_block ()->get_locus ()), - expr.get_locus ()); - } -} - -void -TypeCheckExpr::visit (HIR::IfLetExpr &expr) -{ - // this needs to perform a least upper bound coercion on the blocks and then - // unify the scruintee and arms - TyTy::BaseType *scrutinee_tyty - = TypeCheckExpr::Resolve (expr.get_scrutinee_expr ().get ()); - - for (auto &pattern : expr.get_patterns ()) - { - TyTy::BaseType *kase_arm_ty - = TypeCheckPattern::Resolve (pattern.get (), scrutinee_tyty); - - unify_site (expr.get_mappings ().get_hirid (), - TyTy::TyWithLocation (scrutinee_tyty), - TyTy::TyWithLocation (kase_arm_ty, pattern->get_locus ()), - expr.get_locus ()); - } - - TypeCheckExpr::Resolve (expr.get_if_block ().get ()); - - infered = TyTy::TupleType::get_unit_type (expr.get_mappings ().get_hirid ()); -} - -void -TypeCheckExpr::visit (HIR::IfLetExprConseqElse &expr) -{ - TyTy::BaseType *scrutinee_tyty - = TypeCheckExpr::Resolve (expr.get_scrutinee_expr ().get ()); - - for (auto &pattern : expr.get_patterns ()) - { - TyTy::BaseType *kase_arm_ty - = TypeCheckPattern::Resolve (pattern.get (), scrutinee_tyty); - - unify_site (expr.get_mappings ().get_hirid (), - TyTy::TyWithLocation (scrutinee_tyty), - TyTy::TyWithLocation (kase_arm_ty, pattern->get_locus ()), - expr.get_locus ()); - } - - auto if_blk_resolved = TypeCheckExpr::Resolve (expr.get_if_block ().get ()); - auto else_blk_resolved - = TypeCheckExpr::Resolve (expr.get_else_block ().get ()); - - if (if_blk_resolved->get_kind () == TyTy::NEVER) - infered = else_blk_resolved; - else if (else_blk_resolved->get_kind () == TyTy::NEVER) - infered = if_blk_resolved; - else - { - infered = unify_site ( - expr.get_mappings ().get_hirid (), - TyTy::TyWithLocation (if_blk_resolved, - expr.get_if_block ()->get_locus ()), - TyTy::TyWithLocation (else_blk_resolved, - expr.get_else_block ()->get_locus ()), - expr.get_locus ()); + infered + = unify_site (expr.get_mappings ().get_hirid (), + TyTy::TyWithLocation (if_blk_resolved, + expr.get_if_block ().get_locus ()), + TyTy::TyWithLocation ( + else_blk_resolved, expr.get_else_block ().get_locus ()), + expr.get_locus ()); } } void TypeCheckExpr::visit (HIR::UnsafeBlockExpr &expr) { - infered = TypeCheckExpr::Resolve (expr.get_block_expr ().get ()); + infered = TypeCheckExpr::Resolve (expr.get_block_expr ()); } void @@ -580,7 +593,7 @@ TypeCheckExpr::visit (HIR::BlockExpr &expr) if (!s->is_item ()) continue; - TypeCheckStmt::Resolve (s.get ()); + TypeCheckStmt::Resolve (*s); } for (auto &s : expr.get_statements ()) @@ -588,7 +601,7 @@ TypeCheckExpr::visit (HIR::BlockExpr &expr) if (s->is_item ()) continue; - auto resolved = TypeCheckStmt::Resolve (s.get ()); + auto resolved = TypeCheckStmt::Resolve (*s); if (resolved == nullptr) { rust_error_at (s->get_locus (), "failure to resolve type"); @@ -597,8 +610,7 @@ TypeCheckExpr::visit (HIR::BlockExpr &expr) if (s->is_unit_check_needed () && !resolved->is_unit ()) { - auto unit - = TyTy::TupleType::get_unit_type (s->get_mappings ().get_hirid ()); + auto unit = TyTy::TupleType::get_unit_type (); resolved = unify_site (s->get_mappings ().get_hirid (), TyTy::TyWithLocation (unit), @@ -607,10 +619,9 @@ TypeCheckExpr::visit (HIR::BlockExpr &expr) } if (expr.has_expr ()) - infered = TypeCheckExpr::Resolve (expr.get_final_expr ().get ())->clone (); + infered = TypeCheckExpr::Resolve (expr.get_final_expr ())->clone (); else if (expr.is_tail_reachable ()) - infered - = TyTy::TupleType::get_unit_type (expr.get_mappings ().get_hirid ()); + infered = TyTy::TupleType::get_unit_type (); else if (expr.has_label ()) { TyTy::BaseType *loop_context_type = context->pop_loop_context (); @@ -622,8 +633,7 @@ TypeCheckExpr::visit (HIR::BlockExpr &expr) != TyTy::InferType::GENERAL)); infered = loop_context_type_infered ? loop_context_type - : TyTy::TupleType::get_unit_type ( - expr.get_mappings ().get_hirid ()); + : TyTy::TupleType::get_unit_type (); } else { @@ -663,14 +673,13 @@ TypeCheckExpr::visit (HIR::RangeFromToExpr &expr) // resolve the range expressions and these types must unify then we use that // type to substitute into the ADT - TyTy::BaseType *from_ty - = TypeCheckExpr::Resolve (expr.get_from_expr ().get ()); - TyTy::BaseType *to_ty = TypeCheckExpr::Resolve (expr.get_to_expr ().get ()); + TyTy::BaseType *from_ty = TypeCheckExpr::Resolve (expr.get_from_expr ()); + TyTy::BaseType *to_ty = TypeCheckExpr::Resolve (expr.get_to_expr ()); TyTy::BaseType *unified = unify_site ( expr.get_mappings ().get_hirid (), - TyTy::TyWithLocation (from_ty, expr.get_from_expr ()->get_locus ()), - TyTy::TyWithLocation (to_ty, expr.get_to_expr ()->get_locus ()), + TyTy::TyWithLocation (from_ty, expr.get_from_expr ().get_locus ()), + TyTy::TyWithLocation (to_ty, expr.get_to_expr ().get_locus ()), expr.get_locus ()); // substitute it in @@ -715,8 +724,7 @@ TypeCheckExpr::visit (HIR::RangeFromExpr &expr) // resolve the range expressions and these types must unify then we use that // type to substitute into the ADT - TyTy::BaseType *from_ty - = TypeCheckExpr::Resolve (expr.get_from_expr ().get ()); + TyTy::BaseType *from_ty = TypeCheckExpr::Resolve (expr.get_from_expr ()); // substitute it in std::vector<TyTy::SubstitutionArg> subst_mappings; @@ -760,7 +768,7 @@ TypeCheckExpr::visit (HIR::RangeToExpr &expr) // resolve the range expressions and these types must unify then we use that // type to substitute into the ADT - TyTy::BaseType *from_ty = TypeCheckExpr::Resolve (expr.get_to_expr ().get ()); + TyTy::BaseType *from_ty = TypeCheckExpr::Resolve (expr.get_to_expr ()); // substitute it in std::vector<TyTy::SubstitutionArg> subst_mappings; @@ -774,6 +782,81 @@ TypeCheckExpr::visit (HIR::RangeToExpr &expr) } void +typecheck_inline_asm_operand (HIR::InlineAsm &expr) +{ + const auto &operands = expr.get_operands (); + using RegisterType = AST::InlineAsmOperand::RegisterType; + for (auto &operand : operands) + { + switch (operand.get_register_type ()) + { + case RegisterType::In: { + auto in = operand.get_in (); + TypeCheckExpr::Resolve (*in.expr); + break; + } + case RegisterType::Out: { + auto out = operand.get_out (); + TypeCheckExpr::Resolve (*out.expr); + break; + } + case RegisterType::InOut: { + auto in_out = operand.get_in_out (); + TypeCheckExpr::Resolve (*in_out.expr); + break; + } + case RegisterType::SplitInOut: { + auto split_in_out = operand.get_split_in_out (); + TypeCheckExpr::Resolve (*split_in_out.in_expr); + TypeCheckExpr::Resolve (*split_in_out.out_expr); + break; + } + case RegisterType::Const: { + auto anon_const = operand.get_const ().anon_const; + TypeCheckExpr::Resolve (*anon_const.expr); + break; + } + case RegisterType::Sym: { + auto sym = operand.get_sym (); + TypeCheckExpr::Resolve (*sym.expr); + break; + } + case RegisterType::Label: { + auto label = operand.get_label (); + TypeCheckExpr::Resolve (*label.expr); + break; + } + } + } +} +void +TypeCheckExpr::visit (HIR::InlineAsm &expr) +{ + typecheck_inline_asm_operand (expr); + + // NOTE: Hoise out if we have noreturn as an option + // to return a never type + // TODO : new keyword for memory seems sooooo shaky + if (expr.options.count (AST::InlineAsmOption::NORETURN) == 1) + infered = new TyTy::NeverType (expr.get_mappings ().get_hirid ()); + else + infered = TyTy::TupleType::get_unit_type (); +} + +void +TypeCheckExpr::visit (HIR::LlvmInlineAsm &expr) +{ + for (auto &i : expr.inputs) + TypeCheckExpr::Resolve (*i.expr); + + for (auto &o : expr.outputs) + TypeCheckExpr::Resolve (*o.expr); + + // Black box hint is unit type + infered = TyTy::TupleType::get_unit_type (); +} + +void TypeCheckExpr::visit (HIR::RangeFullExpr &expr) { auto lang_item_type = LangItem::Kind::RANGE_FULL; @@ -832,13 +915,12 @@ TypeCheckExpr::visit (HIR::RangeFromToInclExpr &expr) // resolve the range expressions and these types must unify then we use that // type to substitute into the ADT - TyTy::BaseType *from_ty - = TypeCheckExpr::Resolve (expr.get_from_expr ().get ()); - TyTy::BaseType *to_ty = TypeCheckExpr::Resolve (expr.get_to_expr ().get ()); + TyTy::BaseType *from_ty = TypeCheckExpr::Resolve (expr.get_from_expr ()); + TyTy::BaseType *to_ty = TypeCheckExpr::Resolve (expr.get_to_expr ()); TyTy::BaseType *unified = unify_site ( expr.get_mappings ().get_hirid (), - TyTy::TyWithLocation (from_ty, expr.get_from_expr ()->get_locus ()), - TyTy::TyWithLocation (to_ty, expr.get_to_expr ()->get_locus ()), + TyTy::TyWithLocation (from_ty, expr.get_from_expr ().get_locus ()), + TyTy::TyWithLocation (to_ty, expr.get_to_expr ().get_locus ()), expr.get_locus ()); // substitute it in @@ -855,11 +937,11 @@ TypeCheckExpr::visit (HIR::RangeFromToInclExpr &expr) void TypeCheckExpr::visit (HIR::ArrayIndexExpr &expr) { - auto array_expr_ty = TypeCheckExpr::Resolve (expr.get_array_expr ().get ()); + auto array_expr_ty = TypeCheckExpr::Resolve (expr.get_array_expr ()); if (array_expr_ty->get_kind () == TyTy::TypeKind::ERROR) return; - auto index_expr_ty = TypeCheckExpr::Resolve (expr.get_index_expr ().get ()); + auto index_expr_ty = TypeCheckExpr::Resolve (expr.get_index_expr ()); if (index_expr_ty->get_kind () == TyTy::TypeKind::ERROR) return; @@ -882,10 +964,10 @@ TypeCheckExpr::visit (HIR::ArrayIndexExpr &expr) if (maybe_simple_array_access && direct_array_expr_ty->get_kind () == TyTy::TypeKind::ARRAY) { - unify_site (expr.get_index_expr ()->get_mappings ().get_hirid (), + unify_site (expr.get_index_expr ().get_mappings ().get_hirid (), TyTy::TyWithLocation (size_ty), TyTy::TyWithLocation (index_expr_ty, - expr.get_index_expr ()->get_locus ()), + expr.get_index_expr ().get_locus ()), expr.get_locus ()); TyTy::ArrayType *array_type @@ -912,8 +994,8 @@ TypeCheckExpr::visit (HIR::ArrayIndexExpr &expr) // error[E0277]: the type `[{integer}]` cannot be indexed by `u32` rich_location r (line_table, expr.get_locus ()); - r.add_range (expr.get_array_expr ()->get_locus ()); - r.add_range (expr.get_index_expr ()->get_locus ()); + r.add_range (expr.get_array_expr ().get_locus ()); + r.add_range (expr.get_index_expr ().get_locus ()); rust_error_at (r, ErrorCode::E0277, "the type %qs cannot be indexed by %qs", array_expr_ty->get_name ().c_str (), @@ -923,7 +1005,7 @@ TypeCheckExpr::visit (HIR::ArrayIndexExpr &expr) void TypeCheckExpr::visit (HIR::ArrayExpr &expr) { - HIR::ArrayElems &elements = *expr.get_internal_elements (); + auto &elements = expr.get_internal_elements (); HIR::Expr *capacity_expr = nullptr; TyTy::BaseType *element_type = nullptr; @@ -932,25 +1014,24 @@ TypeCheckExpr::visit (HIR::ArrayExpr &expr) case HIR::ArrayElems::ArrayExprType::COPIED: { HIR::ArrayElemsCopied &elems = static_cast<HIR::ArrayElemsCopied &> (elements); - element_type - = TypeCheckExpr::Resolve (elems.get_elem_to_copy ().get ()); + element_type = TypeCheckExpr::Resolve (elems.get_elem_to_copy ()); auto capacity_type - = TypeCheckExpr::Resolve (elems.get_num_copies_expr ().get ()); + = TypeCheckExpr::Resolve (elems.get_num_copies_expr ()); TyTy::BaseType *expected_ty = nullptr; bool ok = context->lookup_builtin ("usize", &expected_ty); rust_assert (ok); - context->insert_type (elems.get_num_copies_expr ()->get_mappings (), + context->insert_type (elems.get_num_copies_expr ().get_mappings (), expected_ty); - unify_site ( - expr.get_mappings ().get_hirid (), TyTy::TyWithLocation (expected_ty), - TyTy::TyWithLocation (capacity_type, - elems.get_num_copies_expr ()->get_locus ()), - expr.get_locus ()); + unify_site (expr.get_mappings ().get_hirid (), + TyTy::TyWithLocation (expected_ty), + TyTy::TyWithLocation ( + capacity_type, elems.get_num_copies_expr ().get_locus ()), + expr.get_locus ()); - capacity_expr = elems.get_num_copies_expr ().get (); + capacity_expr = &elems.get_num_copies_expr (); } break; @@ -961,7 +1042,7 @@ TypeCheckExpr::visit (HIR::ArrayExpr &expr) std::vector<TyTy::BaseType *> types; for (auto &elem : elems.get_values ()) { - types.push_back (TypeCheckExpr::Resolve (elem.get ())); + types.push_back (TypeCheckExpr::Resolve (*elem)); } // this is a LUB @@ -1005,7 +1086,7 @@ void TypeCheckExpr::visit (HIR::StructExprStruct &struct_expr) { TyTy::BaseType *struct_path_ty - = TypeCheckExpr::Resolve (&struct_expr.get_struct_name ()); + = TypeCheckExpr::Resolve (struct_expr.get_struct_name ()); if (struct_path_ty->get_kind () != TyTy::TypeKind::ADT) { rust_error_at (struct_expr.get_struct_name ().get_locus (), @@ -1037,19 +1118,19 @@ TypeCheckExpr::visit (HIR::StructExprStruct &struct_expr) void TypeCheckExpr::visit (HIR::StructExprStructFields &struct_expr) { - infered = TypeCheckStructExpr::Resolve (&struct_expr); + infered = TypeCheckStructExpr::Resolve (struct_expr); } void TypeCheckExpr::visit (HIR::GroupedExpr &expr) { - infered = TypeCheckExpr::Resolve (expr.get_expr_in_parens ().get ()); + infered = TypeCheckExpr::Resolve (expr.get_expr_in_parens ()); } void TypeCheckExpr::visit (HIR::FieldAccessExpr &expr) { - auto struct_base = TypeCheckExpr::Resolve (expr.get_receiver_expr ().get ()); + auto struct_base = TypeCheckExpr::Resolve (expr.get_receiver_expr ()); // FIXME does this require autoderef here? if (struct_base->get_kind () == TyTy::TypeKind::REF) @@ -1061,45 +1142,130 @@ TypeCheckExpr::visit (HIR::FieldAccessExpr &expr) bool is_valid_type = struct_base->get_kind () == TyTy::TypeKind::ADT; if (!is_valid_type) { - rust_error_at (expr.get_locus (), - "expected algebraic data type got: [%s]", - struct_base->as_string ().c_str ()); + rust_error_at (expr.get_locus (), "expected algebraic data type got %qs", + struct_base->get_name ().c_str ()); return; } TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (struct_base); - rust_assert (!adt->is_enum ()); - rust_assert (adt->number_of_variants () == 1); - + rust_assert (adt->number_of_variants () > 0); TyTy::VariantDef *vaiant = adt->get_variants ().at (0); TyTy::StructFieldType *lookup = nullptr; bool found = vaiant->lookup_field (expr.get_field_name ().as_string (), &lookup, nullptr); - if (!found) + if (!found || adt->is_enum ()) { - rust_error_at (expr.get_locus (), "unknown field [%s] for type [%s]", + rich_location r (line_table, expr.get_locus ()); + r.add_range (expr.get_field_name ().get_locus ()); + rust_error_at (r, ErrorCode::E0609, "no field %qs on type %qs", expr.get_field_name ().as_string ().c_str (), - adt->as_string ().c_str ()); + adt->get_name ().c_str ()); return; } infered = lookup->get_field_type (); } +bool +is_default_fn (const MethodCandidate &candidate) +{ + if (candidate.candidate.is_impl_candidate ()) + { + auto *item = candidate.candidate.item.impl.impl_item; + + if (item->get_impl_item_type () == HIR::ImplItem::FUNCTION) + { + auto &fn = static_cast<HIR::Function &> (*item); + + return fn.is_default (); + } + } + + return false; +} + +void +emit_ambiguous_resolution_error (HIR::MethodCallExpr &expr, + std::set<MethodCandidate> &candidates) +{ + rich_location r (line_table, expr.get_method_name ().get_locus ()); + std::string rich_msg = "multiple " + + expr.get_method_name ().get_segment ().as_string () + + " found"; + + // We have to filter out default candidates + for (auto &c : candidates) + if (!is_default_fn (c)) + r.add_range (c.candidate.locus); + + r.add_fixit_replace (rich_msg.c_str ()); + + rust_error_at (r, ErrorCode::E0592, "duplicate definitions with name %qs", + expr.get_method_name ().get_segment ().as_string ().c_str ()); +} + +// We are allowed to have multiple candidates if they are all specializable +// functions or if all of them except one are specializable functions. +// In the later case, we just return a valid candidate without erroring out +// about ambiguity. If there are two or more specialized functions, then we +// error out. +// +// FIXME: The first case is not handled at the moment, so we error out +tl::optional<const MethodCandidate &> +handle_multiple_candidates (HIR::MethodCallExpr &expr, + std::set<MethodCandidate> &candidates) +{ + auto all_default = true; + tl::optional<const MethodCandidate &> found = tl::nullopt; + + for (auto &c : candidates) + { + if (!is_default_fn (c)) + { + all_default = false; + + // We haven't found a final candidate yet, so we can select + // this one. However, if we already have a candidate, then + // that means there are multiple non-default candidates - we + // must error out + if (!found) + { + found = c; + } + else + { + emit_ambiguous_resolution_error (expr, candidates); + return tl::nullopt; + } + } + } + + // None of the candidates were a non-default (specialized) function, so we + // error out + if (all_default) + { + rust_sorry_at (expr.get_locus (), + "cannot resolve method calls to non-specialized methods " + "(all function candidates are %qs)", + "default"); + return tl::nullopt; + } + + return found; +} + void TypeCheckExpr::visit (HIR::MethodCallExpr &expr) { - auto receiver_tyty = TypeCheckExpr::Resolve (expr.get_receiver ().get ()); + auto receiver_tyty = TypeCheckExpr::Resolve (expr.get_receiver ()); if (receiver_tyty->get_kind () == TyTy::TypeKind::ERROR) { - rust_error_at (expr.get_receiver ()->get_locus (), + rust_error_at (expr.get_receiver ().get_locus (), "failed to resolve receiver in MethodCallExpr"); return; } - context->insert_receiver (expr.get_mappings ().get_hirid (), receiver_tyty); - rust_debug_loc (expr.get_locus (), "attempting to resolve method for %s", receiver_tyty->debug_str ().c_str ()); auto candidates @@ -1116,34 +1282,25 @@ TypeCheckExpr::visit (HIR::MethodCallExpr &expr) return; } - if (candidates.size () > 1) - { - rich_location r (line_table, expr.get_method_name ().get_locus ()); - std::string rich_msg - = "multiple " + expr.get_method_name ().get_segment ().as_string () - + " found"; + tl::optional<const MethodCandidate &> candidate = *candidates.begin (); - for (auto &c : candidates) - r.add_range (c.candidate.locus); + if (candidates.size () > 1) + candidate = handle_multiple_candidates (expr, candidates); - r.add_fixit_replace (rich_msg.c_str ()); + if (!candidate) + return; - rust_error_at ( - r, ErrorCode::E0592, "duplicate definitions with name %qs", - expr.get_method_name ().get_segment ().as_string ().c_str ()); - return; - } + auto found_candidate = *candidate; - auto candidate = *candidates.begin (); rust_debug_loc (expr.get_method_name ().get_locus (), "resolved method to: {%u} {%s} with [%lu] adjustments", - candidate.candidate.ty->get_ref (), - candidate.candidate.ty->debug_str ().c_str (), - (unsigned long) candidate.adjustments.size ()); + found_candidate.candidate.ty->get_ref (), + found_candidate.candidate.ty->debug_str ().c_str (), + (unsigned long) found_candidate.adjustments.size ()); // Get the adjusted self Adjuster adj (receiver_tyty); - TyTy::BaseType *adjusted_self = adj.adjust_type (candidate.adjustments); + TyTy::BaseType *adjusted_self = adj.adjust_type (found_candidate.adjustments); rust_debug ("receiver: %s adjusted self %s", receiver_tyty->debug_str ().c_str (), adjusted_self->debug_str ().c_str ()); @@ -1152,12 +1309,12 @@ TypeCheckExpr::visit (HIR::MethodCallExpr &expr) // stored onto the receiver to so as we don't trigger duplicate deref mappings // ICE when an argument is a method call HirId autoderef_mappings_id - = expr.get_receiver ()->get_mappings ().get_hirid (); + = expr.get_receiver ().get_mappings ().get_hirid (); context->insert_autoderef_mappings (autoderef_mappings_id, - std::move (candidate.adjustments)); + std::move (found_candidate.adjustments)); - PathProbeCandidate &resolved_candidate = candidate.candidate; - TyTy::BaseType *lookup_tyty = candidate.candidate.ty; + PathProbeCandidate &resolved_candidate = found_candidate.candidate; + TyTy::BaseType *lookup_tyty = found_candidate.candidate.ty; NodeId resolved_node_id = resolved_candidate.is_impl_candidate () ? resolved_candidate.item.impl.impl_item->get_impl_mappings () @@ -1184,8 +1341,8 @@ TypeCheckExpr::visit (HIR::MethodCallExpr &expr) fn->prepare_higher_ranked_bounds (); rust_debug_loc (expr.get_locus (), "resolved method call to: {%u} {%s}", - candidate.candidate.ty->get_ref (), - candidate.candidate.ty->debug_str ().c_str ()); + found_candidate.candidate.ty->get_ref (), + found_candidate.candidate.ty->debug_str ().c_str ()); if (resolved_candidate.is_impl_candidate ()) { @@ -1200,7 +1357,7 @@ TypeCheckExpr::visit (HIR::MethodCallExpr &expr) if (impl_self_infer->get_kind () == TyTy::TypeKind::ERROR) { rich_location r (line_table, expr.get_locus ()); - r.add_range (impl.get_type ()->get_locus ()); + r.add_range (impl.get_type ().get_locus ()); rust_error_at ( r, "failed to resolve impl type for method call resolution"); return; @@ -1251,8 +1408,17 @@ TypeCheckExpr::visit (HIR::MethodCallExpr &expr) // store the expected fntype context->insert_type (expr.get_method_name ().get_mappings (), lookup); + if (flag_name_resolution_2_0) + { + auto &nr_ctx = const_cast<Resolver2_0::NameResolutionContext &> ( + Resolver2_0::ImmutableNameResolutionContext::get ().resolver ()); + + nr_ctx.map_usage (Resolver2_0::Usage (expr.get_mappings ().get_nodeid ()), + Resolver2_0::Definition (resolved_node_id)); + } // set up the resolved name on the path - if (resolver->get_name_scope ().decl_was_declared_here (resolved_node_id)) + else if (resolver->get_name_scope ().decl_was_declared_here ( + resolved_node_id)) { resolver->insert_resolved_name (expr.get_mappings ().get_nodeid (), resolved_node_id); @@ -1272,11 +1438,10 @@ TypeCheckExpr::visit (HIR::LoopExpr &expr) { context->push_new_loop_context (expr.get_mappings ().get_hirid (), expr.get_locus ()); - TyTy::BaseType *block_expr - = TypeCheckExpr::Resolve (expr.get_loop_block ().get ()); + TyTy::BaseType *block_expr = TypeCheckExpr::Resolve (expr.get_loop_block ()); if (!block_expr->is_unit ()) { - rust_error_at (expr.get_loop_block ()->get_locus (), + rust_error_at (expr.get_loop_block ().get_locus (), "expected %<()%> got %s", block_expr->as_string ().c_str ()); return; @@ -1290,10 +1455,8 @@ TypeCheckExpr::visit (HIR::LoopExpr &expr) && (((TyTy::InferType *) loop_context_type)->get_infer_kind () != TyTy::InferType::GENERAL)); - infered - = loop_context_type_infered - ? loop_context_type - : TyTy::TupleType::get_unit_type (expr.get_mappings ().get_hirid ()); + infered = loop_context_type_infered ? loop_context_type + : TyTy::TupleType::get_unit_type (); } void @@ -1301,20 +1464,19 @@ TypeCheckExpr::visit (HIR::WhileLoopExpr &expr) { context->push_new_while_loop_context (expr.get_mappings ().get_hirid ()); - TypeCheckExpr::Resolve (expr.get_predicate_expr ().get ()); - TyTy::BaseType *block_expr - = TypeCheckExpr::Resolve (expr.get_loop_block ().get ()); + TypeCheckExpr::Resolve (expr.get_predicate_expr ()); + TyTy::BaseType *block_expr = TypeCheckExpr::Resolve (expr.get_loop_block ()); if (!block_expr->is_unit ()) { - rust_error_at (expr.get_loop_block ()->get_locus (), + rust_error_at (expr.get_loop_block ().get_locus (), "expected %<()%> got %s", block_expr->as_string ().c_str ()); return; } context->pop_loop_context (); - infered = TyTy::TupleType::get_unit_type (expr.get_mappings ().get_hirid ()); + infered = TyTy::TupleType::get_unit_type (); } void @@ -1330,7 +1492,7 @@ TypeCheckExpr::visit (HIR::BreakExpr &expr) if (expr.has_break_expr ()) { TyTy::BaseType *break_expr_tyty - = TypeCheckExpr::Resolve (expr.get_expr ().get ()); + = TypeCheckExpr::Resolve (expr.get_expr ()); TyTy::BaseType *loop_context = context->peek_loop_context (); if (loop_context->get_kind () == TyTy::TypeKind::ERROR) @@ -1345,7 +1507,7 @@ TypeCheckExpr::visit (HIR::BreakExpr &expr) = unify_site (expr.get_mappings ().get_hirid (), TyTy::TyWithLocation (loop_context), TyTy::TyWithLocation (break_expr_tyty, - expr.get_expr ()->get_locus ()), + expr.get_expr ().get_locus ()), expr.get_locus ()); context->swap_head_loop_context (unified_ty); } @@ -1369,8 +1531,9 @@ TypeCheckExpr::visit (HIR::ContinueExpr &expr) void TypeCheckExpr::visit (HIR::BorrowExpr &expr) { - TyTy::BaseType *resolved_base - = TypeCheckExpr::Resolve (expr.get_expr ().get ()); + TyTy::BaseType *resolved_base = TypeCheckExpr::Resolve (expr.get_expr ()); + if (resolved_base->is<TyTy::ErrorType> ()) + return; // In Rust this is valid because of DST's // @@ -1392,6 +1555,15 @@ TypeCheckExpr::visit (HIR::BorrowExpr &expr) } } + if (expr.is_raw_borrow ()) + { + infered = new TyTy::PointerType (expr.get_mappings ().get_hirid (), + TyTy::TyVar (resolved_base->get_ref ()), + expr.get_mut ()); + + return; + } + infered = new TyTy::ReferenceType (expr.get_mappings ().get_hirid (), TyTy::TyVar (resolved_base->get_ref ()), expr.get_mut ()); @@ -1400,8 +1572,7 @@ TypeCheckExpr::visit (HIR::BorrowExpr &expr) void TypeCheckExpr::visit (HIR::DereferenceExpr &expr) { - TyTy::BaseType *resolved_base - = TypeCheckExpr::Resolve (expr.get_expr ().get ()); + TyTy::BaseType *resolved_base = TypeCheckExpr::Resolve (expr.get_expr ()); rust_debug_loc (expr.get_locus (), "attempting deref operator overload"); auto lang_item_type = LangItem::Kind::DEREF; @@ -1442,14 +1613,14 @@ void TypeCheckExpr::visit (HIR::TypeCastExpr &expr) { TyTy::BaseType *expr_to_convert - = TypeCheckExpr::Resolve (expr.get_casted_expr ().get ()); + = TypeCheckExpr::Resolve (expr.get_casted_expr ()); TyTy::BaseType *tyty_to_convert_to - = TypeCheckType::Resolve (expr.get_type_to_convert_to ().get ()); + = TypeCheckType::Resolve (expr.get_type_to_convert_to ()); TyTy::TyWithLocation from (expr_to_convert, - expr.get_casted_expr ()->get_locus ()); + expr.get_casted_expr ().get_locus ()); TyTy::TyWithLocation to (tyty_to_convert_to, - expr.get_type_to_convert_to ()->get_locus ()); + expr.get_type_to_convert_to ().get_locus ()); infered = cast_site (expr.get_mappings ().get_hirid (), from, to, expr.get_locus ()); } @@ -1460,8 +1631,21 @@ TypeCheckExpr::visit (HIR::MatchExpr &expr) // this needs to perform a least upper bound coercion on the blocks and then // unify the scruintee and arms TyTy::BaseType *scrutinee_tyty - = TypeCheckExpr::Resolve (expr.get_scrutinee_expr ().get ()); + = TypeCheckExpr::Resolve (expr.get_scrutinee_expr ()); + // https://github.com/Rust-GCC/gccrs/issues/3231#issuecomment-2462660048 + // https://github.com/rust-lang/rust/blob/3d1dba830a564d1118361345d7ada47a05241f45/compiler/rustc_hir_typeck/src/_match.rs#L32-L36 + if (!expr.has_match_arms ()) + { + // this is a special case where rustc returns ! + TyTy::BaseType *lookup = nullptr; + bool ok = context->lookup_builtin ("!", &lookup); + rust_assert (ok); + infered = lookup->clone (); + return; + } + + bool saw_error = false; std::vector<TyTy::BaseType *> kase_block_tys; for (auto &kase : expr.get_match_cases ()) { @@ -1470,30 +1654,36 @@ TypeCheckExpr::visit (HIR::MatchExpr &expr) for (auto &pattern : kase_arm.get_patterns ()) { TyTy::BaseType *kase_arm_ty - = TypeCheckPattern::Resolve (pattern.get (), scrutinee_tyty); + = TypeCheckPattern::Resolve (*pattern, scrutinee_tyty); if (kase_arm_ty->get_kind () == TyTy ::TypeKind::ERROR) - return; + { + saw_error = true; + continue; + } TyTy::BaseType *checked_kase = unify_site ( expr.get_mappings ().get_hirid (), TyTy::TyWithLocation (scrutinee_tyty, - expr.get_scrutinee_expr ()->get_locus ()), + expr.get_scrutinee_expr ().get_locus ()), TyTy::TyWithLocation (kase_arm_ty, pattern->get_locus ()), expr.get_locus ()); if (checked_kase->get_kind () == TyTy::TypeKind::ERROR) - return; + { + saw_error = true; + continue; + } } // check the kase type - TyTy::BaseType *kase_block_ty - = TypeCheckExpr::Resolve (kase.get_expr ().get ()); + TyTy::BaseType *kase_block_ty = TypeCheckExpr::Resolve (kase.get_expr ()); kase_block_tys.push_back (kase_block_ty); } + if (saw_error) + return; if (kase_block_tys.size () == 0) { - infered - = TyTy::TupleType::get_unit_type (expr.get_mappings ().get_hirid ()); + infered = TyTy::TupleType::get_unit_type (); return; } @@ -1502,9 +1692,10 @@ TypeCheckExpr::visit (HIR::MatchExpr &expr) for (size_t i = 1; i < kase_block_tys.size (); i++) { TyTy::BaseType *kase_ty = kase_block_tys.at (i); - infered = unify_site (expr.get_mappings ().get_hirid (), - TyTy::TyWithLocation (infered), - TyTy::TyWithLocation (kase_ty), expr.get_locus ()); + infered + = coercion_site (expr.get_mappings ().get_hirid (), + TyTy::TyWithLocation (infered), + TyTy::TyWithLocation (kase_ty), expr.get_locus ()); } } @@ -1528,17 +1719,17 @@ TypeCheckExpr::visit (HIR::ClosureExpr &expr) TyTy::BaseType *param_tyty = nullptr; if (p.has_type_given ()) { - param_tyty = TypeCheckType::Resolve (p.get_type ().get ()); + param_tyty = TypeCheckType::Resolve (p.get_type ()); } else { - param_tyty = ClosureParamInfer::Resolve (p.get_pattern ().get ()); + param_tyty = ClosureParamInfer::Resolve (p.get_pattern ()); } TyTy::TyVar param_ty (param_tyty->get_ref ()); parameter_types.push_back (param_ty); - TypeCheckPattern::Resolve (p.get_pattern ().get (), param_ty.get_tyty ()); + TypeCheckPattern::Resolve (p.get_pattern (), param_ty.get_tyty ()); } // we generate an implicit hirid for the closure args @@ -1546,21 +1737,20 @@ TypeCheckExpr::visit (HIR::ClosureExpr &expr) TyTy::TupleType *closure_args = new TyTy::TupleType (implicit_args_id, expr.get_locus (), parameter_types); - context->insert_implicit_type (closure_args); + context->insert_implicit_type (closure_args->get_ref (), closure_args); location_t result_type_locus = expr.has_return_type () - ? expr.get_return_type ()->get_locus () + ? expr.get_return_type ().get_locus () : expr.get_locus (); TyTy::TyVar result_type = expr.has_return_type () ? TyTy::TyVar ( - TypeCheckType::Resolve (expr.get_return_type ().get ())->get_ref ()) + TypeCheckType::Resolve (expr.get_return_type ())->get_ref ()) : TyTy::TyVar::get_implicit_infer_var (expr.get_locus ()); // resolve the block - location_t closure_expr_locus = expr.get_expr ()->get_locus (); - TyTy::BaseType *closure_expr_ty - = TypeCheckExpr::Resolve (expr.get_expr ().get ()); + location_t closure_expr_locus = expr.get_expr ().get_locus (); + TyTy::BaseType *closure_expr_ty = TypeCheckExpr::Resolve (expr.get_expr ()); coercion_site (expr.get_mappings ().get_hirid (), TyTy::TyWithLocation (result_type.get_tyty (), result_type_locus), @@ -1569,7 +1759,24 @@ TypeCheckExpr::visit (HIR::ClosureExpr &expr) // generate the closure type NodeId closure_node_id = expr.get_mappings ().get_nodeid (); - const std::set<NodeId> &captures = resolver->get_captures (closure_node_id); + + // Resolve closure captures + + std::set<NodeId> captures; + if (flag_name_resolution_2_0) + { + auto &nr_ctx = const_cast<Resolver2_0::NameResolutionContext &> ( + Resolver2_0::ImmutableNameResolutionContext::get ().resolver ()); + + if (auto opt_cap = nr_ctx.mappings.lookup_captures (closure_node_id)) + for (auto cap : opt_cap.value ()) + captures.insert (cap); + } + else + { + captures = resolver->get_captures (closure_node_id); + } + infered = new TyTy::ClosureType (ref, id, ident, closure_args, result_type, subst_refs, captures); @@ -1626,10 +1833,10 @@ TypeCheckExpr::visit (HIR::ClosureExpr &expr) } bool -TypeCheckExpr::resolve_operator_overload (LangItem::Kind lang_item_type, - HIR::OperatorExprMeta expr, - TyTy::BaseType *lhs, - TyTy::BaseType *rhs) +TypeCheckExpr::resolve_operator_overload ( + LangItem::Kind lang_item_type, HIR::OperatorExprMeta expr, + TyTy::BaseType *lhs, TyTy::BaseType *rhs, + HIR::PathIdentSegment specified_segment) { // look up lang item for arithmetic type std::string associated_item_name = LangItem::ToString (lang_item_type); @@ -1647,7 +1854,9 @@ TypeCheckExpr::resolve_operator_overload (LangItem::Kind lang_item_type, current_context = context->peek_context (); } - auto segment = HIR::PathIdentSegment (associated_item_name); + auto segment = specified_segment.is_error () + ? HIR::PathIdentSegment (associated_item_name) + : specified_segment; auto candidates = MethodResolver::Probe (lhs, segment); // remove any recursive candidates @@ -1700,9 +1909,6 @@ TypeCheckExpr::resolve_operator_overload (LangItem::Kind lang_item_type, context->insert_autoderef_mappings (expr.get_lvalue_mappings ().get_hirid (), std::move (candidate.adjustments)); - // now its just like a method-call-expr - context->insert_receiver (expr.get_mappings ().get_hirid (), lhs); - PathProbeCandidate &resolved_candidate = candidate.candidate; TyTy::BaseType *lookup_tyty = candidate.candidate.ty; NodeId resolved_node_id @@ -1747,13 +1953,23 @@ TypeCheckExpr::resolve_operator_overload (LangItem::Kind lang_item_type, HIR::ImplBlock *parent = impl_item.first; HIR::Function *fn = impl_item.second; - if (parent->has_trait_ref () - && fn->get_function_name ().as_string ().compare ( - associated_item_name) - == 0) + bool is_deref = lang_item_type == LangItem::Kind::DEREF + || lang_item_type == LangItem::Kind::DEREF_MUT; + bool is_deref_match = fn->get_function_name ().as_string ().compare ( + LangItem::ToString (LangItem::Kind::DEREF)) + == 0 + || fn->get_function_name ().as_string ().compare ( + LangItem::ToString (LangItem::Kind::DEREF_MUT)) + == 0; + + bool is_recursive_op + = fn->get_function_name ().as_string ().compare (associated_item_name) + == 0 + || (is_deref && is_deref_match); + if (parent->has_trait_ref () && is_recursive_op) { TraitReference *trait_reference - = TraitResolver::Lookup (*parent->get_trait_ref ().get ()); + = TraitResolver::Lookup (parent->get_trait_ref ()); if (!trait_reference->is_error ()) { TyTy::BaseType *lookup = nullptr; @@ -1767,7 +1983,8 @@ TypeCheckExpr::resolve_operator_overload (LangItem::Kind lang_item_type, bool is_lang_item_impl = trait_reference->get_mappings ().get_defid () - == respective_lang_item_id; + == respective_lang_item_id + || (is_deref && is_deref_match); bool self_is_lang_item_self = fntype->get_self_type ()->is_equal (*adjusted_self); bool recursive_operator_overload @@ -1792,11 +2009,11 @@ TypeCheckExpr::resolve_operator_overload (LangItem::Kind lang_item_type, // type check the arguments if required TyTy::FnType *type = static_cast<TyTy::FnType *> (lookup); rust_assert (type->num_params () > 0); - auto fnparam = type->param_at (0); + auto &fnparam = type->param_at (0); // typecheck the self unify_site (expr.get_mappings ().get_hirid (), - TyTy::TyWithLocation (fnparam.second), + TyTy::TyWithLocation (fnparam.get_type ()), TyTy::TyWithLocation (adjusted_self), expr.get_locus ()); if (rhs == nullptr) { @@ -1805,9 +2022,9 @@ TypeCheckExpr::resolve_operator_overload (LangItem::Kind lang_item_type, else { rust_assert (type->num_params () == 2); - auto fnparam = type->param_at (1); + auto &fnparam = type->param_at (1); unify_site (expr.get_mappings ().get_hirid (), - TyTy::TyWithLocation (fnparam.second), + TyTy::TyWithLocation (fnparam.get_type ()), TyTy::TyWithLocation (rhs), expr.get_locus ()); } @@ -1823,8 +2040,19 @@ TypeCheckExpr::resolve_operator_overload (LangItem::Kind lang_item_type, context->insert_operator_overload (expr.get_mappings ().get_hirid (), type); // set up the resolved name on the path - resolver->insert_resolved_name (expr.get_mappings ().get_nodeid (), - resolved_node_id); + if (flag_name_resolution_2_0) + { + auto &nr_ctx = const_cast<Resolver2_0::NameResolutionContext &> ( + Resolver2_0::ImmutableNameResolutionContext::get ().resolver ()); + + nr_ctx.map_usage (Resolver2_0::Usage (expr.get_mappings ().get_nodeid ()), + Resolver2_0::Definition (resolved_node_id)); + } + else + { + resolver->insert_resolved_name (expr.get_mappings ().get_nodeid (), + resolved_node_id); + } // return the result of the function back infered = function_ret_tyty; @@ -1921,11 +2149,10 @@ TypeCheckExpr::resolve_fn_trait_call (HIR::CallExpr &expr, // store the adjustments for code-generation to know what to do which must be // stored onto the receiver to so as we don't trigger duplicate deref mappings // ICE when an argument is a method call - HIR::Expr *fnexpr = expr.get_fnexpr ().get (); - HirId autoderef_mappings_id = fnexpr->get_mappings ().get_hirid (); + HIR::Expr &fnexpr = expr.get_fnexpr (); + HirId autoderef_mappings_id = fnexpr.get_mappings ().get_hirid (); context->insert_autoderef_mappings (autoderef_mappings_id, std::move (candidate.adjustments)); - context->insert_receiver (expr.get_mappings ().get_hirid (), receiver_tyty); PathProbeCandidate &resolved_candidate = candidate.candidate; TyTy::BaseType *lookup_tyty = candidate.candidate.ty; @@ -1959,7 +2186,7 @@ TypeCheckExpr::resolve_fn_trait_call (HIR::CallExpr &expr, std::vector<TyTy::TyVar> call_args; for (auto &arg : expr.get_arguments ()) { - TyTy::BaseType *a = TypeCheckExpr::Resolve (arg.get ()); + TyTy::BaseType *a = TypeCheckExpr::Resolve (*arg); call_args.push_back (TyTy::TyVar (a->get_ref ())); } @@ -1993,8 +2220,32 @@ TypeCheckExpr::resolve_fn_trait_call (HIR::CallExpr &expr, context->insert_operator_overload (expr.get_mappings ().get_hirid (), fn); // set up the resolved name on the path - resolver->insert_resolved_name (expr.get_mappings ().get_nodeid (), - resolved_node_id); + if (flag_name_resolution_2_0) + { + auto &nr_ctx = const_cast<Resolver2_0::NameResolutionContext &> ( + Resolver2_0::ImmutableNameResolutionContext::get ().resolver ()); + + auto existing = nr_ctx.lookup (expr.get_mappings ().get_nodeid ()); + if (existing) + rust_assert (*existing == resolved_node_id); + else + nr_ctx.map_usage (Resolver2_0::Usage ( + expr.get_mappings ().get_nodeid ()), + Resolver2_0::Definition (resolved_node_id)); + } + else + { + NodeId existing = UNKNOWN_NODEID; + bool ok + = resolver->lookup_resolved_name (expr.get_mappings ().get_nodeid (), + &existing); + + if (ok) + rust_assert (existing == resolved_node_id); + else + resolver->insert_resolved_name (expr.get_mappings ().get_nodeid (), + resolved_node_id); + } // return the result of the function back *result = function_ret_tyty; diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.h b/gcc/rust/typecheck/rust-hir-type-check-expr.h index 45fc330..79121b3 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-expr.h +++ b/gcc/rust/typecheck/rust-hir-type-check-expr.h @@ -29,7 +29,7 @@ namespace Resolver { class TypeCheckExpr : private TypeCheckBase, private HIR::HIRExpressionVisitor { public: - static TyTy::BaseType *Resolve (HIR::Expr *expr); + static TyTy::BaseType *Resolve (HIR::Expr &expr); void visit (HIR::TupleIndexExpr &expr) override; void visit (HIR::TupleExpr &expr) override; @@ -45,8 +45,6 @@ public: void visit (HIR::NegationExpr &expr) override; void visit (HIR::IfExpr &expr) override; void visit (HIR::IfExprConseqElse &expr) override; - void visit (HIR::IfLetExpr &expr) override; - void visit (HIR::IfLetExprConseqElse &) override; void visit (HIR::BlockExpr &expr) override; void visit (HIR::UnsafeBlockExpr &expr) override; void visit (HIR::ArrayIndexExpr &expr) override; @@ -71,6 +69,8 @@ public: void visit (HIR::RangeFromToInclExpr &expr) override; void visit (HIR::WhileLoopExpr &expr) override; void visit (HIR::ClosureExpr &expr) override; + void visit (HIR::InlineAsm &expr) override; + void visit (HIR::LlvmInlineAsm &expr) override; // TODO void visit (HIR::ErrorPropagationExpr &) override {} @@ -98,7 +98,9 @@ public: protected: bool resolve_operator_overload (LangItem::Kind lang_item_type, HIR::OperatorExprMeta expr, - TyTy::BaseType *lhs, TyTy::BaseType *rhs); + TyTy::BaseType *lhs, TyTy::BaseType *rhs, + HIR::PathIdentSegment specified_segment + = HIR::PathIdentSegment::create_error ()); bool resolve_fn_trait_call (HIR::CallExpr &expr, TyTy::BaseType *function_tyty, diff --git a/gcc/rust/typecheck/rust-hir-type-check-implitem.cc b/gcc/rust/typecheck/rust-hir-type-check-implitem.cc index 58d59d9..bc7f6dc 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-implitem.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-implitem.cc @@ -18,12 +18,18 @@ #include "rust-hir-type-check-implitem.h" #include "rust-diagnostics.h" +#include "rust-hir-full-decls.h" +#include "rust-hir-pattern.h" #include "rust-hir-type-check-base.h" #include "rust-hir-type-check-type.h" #include "rust-hir-type-check-expr.h" #include "rust-hir-type-check-pattern.h" #include "rust-type-util.h" #include "rust-tyty.h" +#include "rust-immutable-name-resolution-context.h" + +// for flag_name_resolution_2_0 +#include "options.h" namespace Rust { namespace Resolver { @@ -34,27 +40,26 @@ TypeCheckTopLevelExternItem::TypeCheckTopLevelExternItem ( {} TyTy::BaseType * -TypeCheckTopLevelExternItem::Resolve (HIR::ExternalItem *item, +TypeCheckTopLevelExternItem::Resolve (HIR::ExternalItem &item, const HIR::ExternBlock &parent) { // is it already resolved? auto context = TypeCheckContext::get (); TyTy::BaseType *resolved = nullptr; bool already_resolved - = context->lookup_type (item->get_mappings ().get_hirid (), &resolved); + = context->lookup_type (item.get_mappings ().get_hirid (), &resolved); if (already_resolved) return resolved; TypeCheckTopLevelExternItem resolver (parent); - item->accept_vis (resolver); + item.accept_vis (resolver); return resolver.resolved; } void TypeCheckTopLevelExternItem::visit (HIR::ExternalStaticItem &item) { - TyTy::BaseType *actual_type - = TypeCheckType::Resolve (item.get_item_type ().get ()); + TyTy::BaseType *actual_type = TypeCheckType::Resolve (item.get_item_type ()); context->insert_type (item.get_mappings (), actual_type); resolved = actual_type; @@ -68,33 +73,8 @@ TypeCheckTopLevelExternItem::visit (HIR::ExternalFunctionItem &function) std::vector<TyTy::SubstitutionParamMapping> substitutions; if (function.has_generics ()) { - for (auto &generic_param : function.get_generic_params ()) - { - switch (generic_param.get ()->get_kind ()) - { - case HIR::GenericParam::GenericKind::LIFETIME: - context->intern_and_insert_lifetime ( - static_cast<HIR::LifetimeParam &> (*generic_param) - .get_lifetime ()); - // TODO: handle bounds - break; - case HIR::GenericParam::GenericKind::CONST: - // FIXME: Skipping Lifetime and Const completely until better - // handling. - break; - - case HIR::GenericParam::GenericKind::TYPE: { - auto param_type - = TypeResolveGenericParam::Resolve (generic_param.get ()); - context->insert_type (generic_param->get_mappings (), - param_type); - - substitutions.push_back (TyTy::SubstitutionParamMapping ( - static_cast<HIR::TypeParam &> (*generic_param), param_type)); - } - break; - } - } + resolve_generic_params (function.get_generic_params (), substitutions, + true /*is_foreign*/, parent.get_abi ()); } TyTy::RegionConstraints region_constraints; @@ -102,19 +82,17 @@ TypeCheckTopLevelExternItem::visit (HIR::ExternalFunctionItem &function) { for (auto &where_clause_item : function.get_where_clause ().get_items ()) { - ResolveWhereClauseItem::Resolve (*where_clause_item.get (), + ResolveWhereClauseItem::Resolve (*where_clause_item, region_constraints); } } TyTy::BaseType *ret_type = nullptr; if (!function.has_return_type ()) - ret_type - = TyTy::TupleType::get_unit_type (function.get_mappings ().get_hirid ()); + ret_type = TyTy::TupleType::get_unit_type (); else { - auto resolved - = TypeCheckType::Resolve (function.get_return_type ().get ()); + auto resolved = TypeCheckType::Resolve (function.get_return_type ()); if (resolved == nullptr) { rust_error_at (function.get_locus (), @@ -124,14 +102,14 @@ TypeCheckTopLevelExternItem::visit (HIR::ExternalFunctionItem &function) ret_type = resolved->clone (); ret_type->set_ref ( - function.get_return_type ()->get_mappings ().get_hirid ()); + function.get_return_type ().get_mappings ().get_hirid ()); } - std::vector<std::pair<HIR::Pattern *, TyTy::BaseType *> > params; + std::vector<TyTy::FnParam> params; for (auto ¶m : function.get_function_params ()) { // get the name as well required for later on - auto param_tyty = TypeCheckType::Resolve (param.get_type ().get ()); + auto param_tyty = TypeCheckType::Resolve (param.get_type ()); // these are implicit mappings and not used auto crate_num = mappings.get_current_crate (); @@ -139,14 +117,12 @@ TypeCheckTopLevelExternItem::visit (HIR::ExternalFunctionItem &function) mappings.get_next_hir_id (crate_num), UNKNOWN_LOCAL_DEFID); - HIR::IdentifierPattern *param_pattern - = new HIR::IdentifierPattern (mapping, param.get_param_name (), - UNDEF_LOCATION, false, Mutability::Imm, - std::unique_ptr<HIR::Pattern> (nullptr)); + auto param_pattern = std::make_unique<HIR::IdentifierPattern> ( + HIR::IdentifierPattern (mapping, param.get_param_name (), + UNDEF_LOCATION, false, Mutability::Imm, + std::unique_ptr<HIR::Pattern> (nullptr))); - params.push_back ( - std::pair<HIR::Pattern *, TyTy::BaseType *> (param_pattern, - param_tyty)); + params.push_back (TyTy::FnParam (std::move (param_pattern), param_tyty)); context->insert_type (param.get_mappings (), param_tyty); @@ -188,132 +164,11 @@ void TypeCheckTopLevelExternItem::visit (HIR::ExternalTypeItem &type) { rust_sorry_at (type.get_locus (), "extern types are not supported yet"); - // auto binder_pin = context->push_clean_lifetime_resolver (); - - // std::vector<TyTy::SubstitutionParamMapping> substitutions; - // if (function.has_generics ()) - // { - // for (auto &generic_param : function.get_generic_params ()) - // { - // switch (generic_param.get ()->get_kind ()) - // { - // case HIR::GenericParam::GenericKind::LIFETIME: - // context->intern_and_insert_lifetime ( - // static_cast<HIR::LifetimeParam &> (*generic_param) - // .get_lifetime ()); - // // TODO: handle bounds - // break; - // case HIR::GenericParam::GenericKind::CONST: - // // FIXME: Skipping Lifetime and Const completely until better - // // handling. - // break; - - // case HIR::GenericParam::GenericKind::TYPE: { - // auto param_type - // = TypeResolveGenericParam::Resolve (generic_param.get ()); - // context->insert_type (generic_param->get_mappings (), - // param_type); - - // substitutions.push_back (TyTy::SubstitutionParamMapping ( - // static_cast<HIR::TypeParam &> (*generic_param), param_type)); - // } - // break; - // } - // } - // } - - // TyTy::RegionConstraints region_constraints; - // if (function.has_where_clause ()) - // { - // for (auto &where_clause_item : function.get_where_clause ().get_items - // ()) - // { - // ResolveWhereClauseItem::Resolve (*where_clause_item.get (), - // region_constraints); - // } - // } - - // TyTy::BaseType *ret_type = nullptr; - // if (!function.has_return_type ()) - // ret_type - // = TyTy::TupleType::get_unit_type (function.get_mappings ().get_hirid - // ()); - // else - // { - // auto resolved - // = TypeCheckType::Resolve (function.get_return_type ().get ()); - // if (resolved == nullptr) - // { - // rust_error_at (function.get_locus (), - // "failed to resolve return type"); - // return; - // } - - // ret_type = resolved->clone (); - // ret_type->set_ref ( - // function.get_return_type ()->get_mappings ().get_hirid ()); - // } - - // std::vector<std::pair<HIR::Pattern *, TyTy::BaseType *> > params; - // for (auto ¶m : function.get_function_params ()) - // { - // // get the name as well required for later on - // auto param_tyty = TypeCheckType::Resolve (param.get_type ().get ()); - - // // these are implicit mappings and not used - // auto crate_num = mappings->get_current_crate (); - // Analysis::NodeMapping mapping (crate_num, mappings->get_next_node_id - // (), - // mappings->get_next_hir_id (crate_num), - // UNKNOWN_LOCAL_DEFID); - - // HIR::IdentifierPattern *param_pattern - // = new HIR::IdentifierPattern (mapping, param.get_param_name (), - // UNDEF_LOCATION, false, Mutability::Imm, - // std::unique_ptr<HIR::Pattern> (nullptr)); - - // params.push_back ( - // std::pair<HIR::Pattern *, TyTy::BaseType *> (param_pattern, - // param_tyty)); - - // context->insert_type (param.get_mappings (), param_tyty); - - // // FIXME do we need error checking for patterns here? - // // see https://github.com/Rust-GCC/gccrs/issues/995 - // } - - // uint8_t flags = TyTy::FnType::FNTYPE_IS_EXTERN_FLAG; - // if (function.is_variadic ()) - // { - // flags |= TyTy::FnType::FNTYPE_IS_VARADIC_FLAG; - // if (parent.get_abi () != Rust::ABI::C) - // { - // rust_error_at ( - // function.get_locus (), ErrorCode::E0045, - // "C-variadic function must have C or cdecl calling convention"); - // } - // } - - // RustIdent ident{ - // CanonicalPath::new_seg (function.get_mappings ().get_nodeid (), - // function.get_item_name ().as_string ()), - // function.get_locus ()}; - - // auto fnType = new TyTy::FnType ( - // function.get_mappings ().get_hirid (), - // function.get_mappings ().get_defid (), - // function.get_item_name ().as_string (), ident, flags, parent.get_abi (), - // std::move (params), ret_type, std::move (substitutions), - // TyTy::SubstitutionArgumentMappings::empty ( - // context->get_lifetime_resolver ().get_num_bound_regions ()), - // region_constraints); - - // context->insert_type (function.get_mappings (), fnType); - // resolved = fnType; + // TODO } TypeCheckImplItem::TypeCheckImplItem ( - HIR::ImplBlock *parent, TyTy::BaseType *self, + HIR::ImplBlock &parent, TyTy::BaseType *self, std::vector<TyTy::SubstitutionParamMapping> substitutions) : TypeCheckBase (), parent (parent), self (self), substitutions (substitutions) @@ -321,20 +176,24 @@ TypeCheckImplItem::TypeCheckImplItem ( TyTy::BaseType * TypeCheckImplItem::Resolve ( - HIR::ImplBlock *parent, HIR::ImplItem *item, TyTy::BaseType *self, + HIR::ImplBlock &parent, HIR::ImplItem &item, TyTy::BaseType *self, std::vector<TyTy::SubstitutionParamMapping> substitutions) { // is it already resolved? auto context = TypeCheckContext::get (); TyTy::BaseType *resolved = nullptr; bool already_resolved - = context->lookup_type (item->get_impl_mappings ().get_hirid (), &resolved); + = context->lookup_type (item.get_impl_mappings ().get_hirid (), &resolved); if (already_resolved) return resolved; // resolve TypeCheckImplItem resolver (parent, self, substitutions); - item->accept_vis (resolver); + resolver.context->block_context ().enter ( + TypeCheckBlockContextItem (&parent)); + item.accept_vis (resolver); + resolver.context->block_context ().exit (); + return resolver.result; } @@ -355,12 +214,10 @@ TypeCheckImplItem::visit (HIR::Function &function) TyTy::BaseType *ret_type = nullptr; if (!function.has_function_return_type ()) - ret_type - = TyTy::TupleType::get_unit_type (function.get_mappings ().get_hirid ()); + ret_type = TyTy::TupleType::get_unit_type (); else { - auto resolved - = TypeCheckType::Resolve (function.get_return_type ().get ()); + auto resolved = TypeCheckType::Resolve (function.get_return_type ()); if (resolved == nullptr) { rust_error_at (function.get_locus (), @@ -370,10 +227,10 @@ TypeCheckImplItem::visit (HIR::Function &function) ret_type = resolved->clone (); ret_type->set_ref ( - function.get_return_type ()->get_mappings ().get_hirid ()); + function.get_return_type ().get_mappings ().get_hirid ()); } - std::vector<std::pair<HIR::Pattern *, TyTy::BaseType *> > params; + std::vector<TyTy::FnParam> params; if (function.is_method ()) { // these are implicit mappings and not used @@ -385,18 +242,20 @@ TypeCheckImplItem::visit (HIR::Function &function) // add the synthetic self param at the front, this is a placeholder for // compilation to know parameter names. The types are ignored but we // reuse the HIR identifier pattern which requires it - HIR::SelfParam &self_param = function.get_self_param (); + HIR::SelfParam &self_param = function.get_self_param_unchecked (); // FIXME: which location should be used for Rust::Identifier for `self`? - HIR::IdentifierPattern *self_pattern = new HIR::IdentifierPattern ( - mapping, {"self"}, self_param.get_locus (), self_param.is_ref (), - self_param.get_mut (), std::unique_ptr<HIR::Pattern> (nullptr)); + std::unique_ptr<HIR::Pattern> self_pattern + = std::make_unique<HIR::IdentifierPattern> ( + HIR::IdentifierPattern (mapping, {"self"}, self_param.get_locus (), + self_param.is_ref (), self_param.get_mut (), + std::unique_ptr<HIR::Pattern> (nullptr))); // might have a specified type TyTy::BaseType *self_type = nullptr; if (self_param.has_type ()) { - std::unique_ptr<HIR::Type> &specified_type = self_param.get_type (); - self_type = TypeCheckType::Resolve (specified_type.get ()); + auto &specified_type = self_param.get_type (); + self_type = TypeCheckType::Resolve (specified_type); } else { @@ -408,13 +267,21 @@ TypeCheckImplItem::visit (HIR::Function &function) break; case HIR::SelfParam::IMM_REF: { - auto region = context->lookup_and_resolve_lifetime ( - self_param.get_lifetime ()); - if (!region.has_value ()) + tl::optional<TyTy::Region> region; + if (self_param.has_lifetime ()) { - rust_inform (self_param.get_locus (), - "failed to resolve lifetime"); - region = TyTy::Region::make_anonymous (); // FIXME + region = context->lookup_and_resolve_lifetime ( + self_param.get_lifetime ()); + if (!region.has_value ()) + { + rust_inform (self_param.get_locus (), + "failed to resolve lifetime"); + return; + } + } + else + { + region = TyTy::Region::make_anonymous (); } self_type = new TyTy::ReferenceType ( self_param.get_mappings ().get_hirid (), @@ -424,13 +291,21 @@ TypeCheckImplItem::visit (HIR::Function &function) break; case HIR::SelfParam::MUT_REF: { - auto region = context->lookup_and_resolve_lifetime ( - self_param.get_lifetime ()); - if (!region.has_value ()) + tl::optional<TyTy::Region> region; + if (self_param.has_lifetime ()) + { + region = context->lookup_and_resolve_lifetime ( + self_param.get_lifetime ()); + if (!region.has_value ()) + { + rust_error_at (self_param.get_locus (), + "failed to resolve lifetime"); + return; + } + } + else { - rust_error_at (self_param.get_locus (), - "failed to resolve lifetime"); - return; + region = TyTy::Region::make_anonymous (); } self_type = new TyTy::ReferenceType ( self_param.get_mappings ().get_hirid (), @@ -446,23 +321,38 @@ TypeCheckImplItem::visit (HIR::Function &function) } context->insert_type (self_param.get_mappings (), self_type); - params.push_back ( - std::pair<HIR::Pattern *, TyTy::BaseType *> (self_pattern, self_type)); + params.push_back (TyTy::FnParam (std::move (self_pattern), self_type)); } for (auto ¶m : function.get_function_params ()) { // get the name as well required for later on - auto param_tyty = TypeCheckType::Resolve (param.get_type ().get ()); - params.push_back (std::pair<HIR::Pattern *, TyTy::BaseType *> ( - param.get_param_name ().get (), param_tyty)); + auto param_tyty = TypeCheckType::Resolve (param.get_type ()); context->insert_type (param.get_mappings (), param_tyty); - TypeCheckPattern::Resolve (param.get_param_name ().get (), param_tyty); + TypeCheckPattern::Resolve (param.get_param_name (), param_tyty); + + params.push_back ( + TyTy::FnParam (param.get_param_name ().clone_pattern (), param_tyty)); + } + + tl::optional<CanonicalPath> canonical_path; + + if (flag_name_resolution_2_0) + { + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); + + canonical_path = nr_ctx.values.to_canonical_path ( + function.get_mappings ().get_nodeid ()); + } + else + { + canonical_path = mappings.lookup_canonical_path ( + function.get_mappings ().get_nodeid ()); } - auto canonical_path - = mappings.lookup_canonical_path (function.get_mappings ().get_nodeid ()); + rust_assert (canonical_path.has_value ()); RustIdent ident{*canonical_path, function.get_locus ()}; auto fnType = new TyTy::FnType ( @@ -485,17 +375,16 @@ TypeCheckImplItem::visit (HIR::Function &function) context->push_return_type (TypeCheckContextItem (parent, &function), expected_ret_tyty); - auto block_expr_ty - = TypeCheckExpr::Resolve (function.get_definition ().get ()); + auto block_expr_ty = TypeCheckExpr::Resolve (function.get_definition ()); location_t fn_return_locus = function.has_function_return_type () - ? function.get_return_type ()->get_locus () + ? function.get_return_type ().get_locus () : function.get_locus (); - coercion_site (function.get_definition ()->get_mappings ().get_hirid (), + coercion_site (function.get_definition ().get_mappings ().get_hirid (), TyTy::TyWithLocation (expected_ret_tyty, fn_return_locus), TyTy::TyWithLocation (block_expr_ty), - function.get_definition ()->get_locus ()); + function.get_definition ().get_locus ()); context->pop_return_type (); } @@ -503,14 +392,13 @@ TypeCheckImplItem::visit (HIR::Function &function) void TypeCheckImplItem::visit (HIR::ConstantItem &constant) { - TyTy::BaseType *type = TypeCheckType::Resolve (constant.get_type ().get ()); - TyTy::BaseType *expr_type - = TypeCheckExpr::Resolve (constant.get_expr ().get ()); + TyTy::BaseType *type = TypeCheckType::Resolve (constant.get_type ()); + TyTy::BaseType *expr_type = TypeCheckExpr::Resolve (constant.get_expr ()); TyTy::BaseType *unified = unify_site ( constant.get_mappings ().get_hirid (), - TyTy::TyWithLocation (type, constant.get_type ()->get_locus ()), - TyTy::TyWithLocation (expr_type, constant.get_expr ()->get_locus ()), + TyTy::TyWithLocation (type, constant.get_type ().get_locus ()), + TyTy::TyWithLocation (expr_type, constant.get_expr ().get_locus ()), constant.get_locus ()); context->insert_type (constant.get_mappings (), unified); result = unified; @@ -525,7 +413,7 @@ TypeCheckImplItem::visit (HIR::TypeAlias &alias) resolve_generic_params (alias.get_generic_params (), substitutions); TyTy::BaseType *actual_type - = TypeCheckType::Resolve (alias.get_type_aliased ().get ()); + = TypeCheckType::Resolve (alias.get_type_aliased ()); context->insert_type (alias.get_mappings (), actual_type); result = actual_type; @@ -538,7 +426,7 @@ TypeCheckImplItem::visit (HIR::TypeAlias &alias) } TypeCheckImplItemWithTrait::TypeCheckImplItemWithTrait ( - HIR::ImplBlock *parent, TyTy::BaseType *self, + HIR::ImplBlock &parent, TyTy::BaseType *self, TyTy::TypeBoundPredicate &trait_reference, std::vector<TyTy::SubstitutionParamMapping> substitutions) : TypeCheckBase (), trait_reference (trait_reference), @@ -550,13 +438,13 @@ TypeCheckImplItemWithTrait::TypeCheckImplItemWithTrait ( TyTy::TypeBoundPredicateItem TypeCheckImplItemWithTrait::Resolve ( - HIR::ImplBlock *parent, HIR::ImplItem *item, TyTy::BaseType *self, + HIR::ImplBlock &parent, HIR::ImplItem &item, TyTy::BaseType *self, TyTy::TypeBoundPredicate &trait_reference, std::vector<TyTy::SubstitutionParamMapping> substitutions) { TypeCheckImplItemWithTrait resolver (parent, self, trait_reference, substitutions); - item->accept_vis (resolver); + item.accept_vis (resolver); return resolver.resolved_trait_item; } @@ -565,7 +453,7 @@ TypeCheckImplItemWithTrait::visit (HIR::ConstantItem &constant) { // normal resolution of the item TyTy::BaseType *lookup - = TypeCheckImplItem::Resolve (parent, &constant, self, substitutions); + = TypeCheckImplItem::Resolve (parent, constant, self, substitutions); // map the impl item to the associated trait item const auto tref = trait_reference.get (); @@ -618,7 +506,7 @@ TypeCheckImplItemWithTrait::visit (HIR::TypeAlias &type) { // normal resolution of the item TyTy::BaseType *lookup - = TypeCheckImplItem::Resolve (parent, &type, self, substitutions); + = TypeCheckImplItem::Resolve (parent, type, self, substitutions); // map the impl item to the associated trait item const auto tref = trait_reference.get (); @@ -679,7 +567,7 @@ TypeCheckImplItemWithTrait::visit (HIR::Function &function) { // normal resolution of the item TyTy::BaseType *lookup - = TypeCheckImplItem::Resolve (parent, &function, self, substitutions); + = TypeCheckImplItem::Resolve (parent, function, self, substitutions); // map the impl item to the associated trait item const auto tref = trait_reference.get (); diff --git a/gcc/rust/typecheck/rust-hir-type-check-implitem.h b/gcc/rust/typecheck/rust-hir-type-check-implitem.h index 4fb2256..14f6a05 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-implitem.h +++ b/gcc/rust/typecheck/rust-hir-type-check-implitem.h @@ -29,7 +29,7 @@ class TypeCheckTopLevelExternItem : public TypeCheckBase, public HIR::HIRExternalItemVisitor { public: - static TyTy::BaseType *Resolve (HIR::ExternalItem *item, + static TyTy::BaseType *Resolve (HIR::ExternalItem &item, const HIR::ExternBlock &parent); void visit (HIR::ExternalStaticItem &item) override; @@ -47,7 +47,7 @@ class TypeCheckImplItem : public TypeCheckBase, public HIR::HIRImplVisitor { public: static TyTy::BaseType * - Resolve (HIR::ImplBlock *parent, HIR::ImplItem *item, TyTy::BaseType *self, + Resolve (HIR::ImplBlock &parent, HIR::ImplItem &item, TyTy::BaseType *self, std::vector<TyTy::SubstitutionParamMapping> substitutions); void visit (HIR::Function &function) override; @@ -55,10 +55,10 @@ public: void visit (HIR::TypeAlias &type_alias) override; protected: - TypeCheckImplItem (HIR::ImplBlock *parent, TyTy::BaseType *self, + TypeCheckImplItem (HIR::ImplBlock &parent, TyTy::BaseType *self, std::vector<TyTy::SubstitutionParamMapping> substitutions); - HIR::ImplBlock *parent; + HIR::ImplBlock &parent; TyTy::BaseType *self; std::vector<TyTy::SubstitutionParamMapping> substitutions; @@ -70,7 +70,7 @@ class TypeCheckImplItemWithTrait : public TypeCheckBase, { public: static TyTy::TypeBoundPredicateItem - Resolve (HIR::ImplBlock *parent, HIR::ImplItem *item, TyTy::BaseType *self, + Resolve (HIR::ImplBlock &parent, HIR::ImplItem &item, TyTy::BaseType *self, TyTy::TypeBoundPredicate &trait_reference, std::vector<TyTy::SubstitutionParamMapping> substitutions); @@ -86,7 +86,7 @@ protected: private: TypeCheckImplItemWithTrait ( - HIR::ImplBlock *parent, TyTy::BaseType *self, + HIR::ImplBlock &parent, TyTy::BaseType *self, TyTy::TypeBoundPredicate &trait_reference, std::vector<TyTy::SubstitutionParamMapping> substitutions); @@ -95,7 +95,7 @@ private: TyTy::TypeBoundPredicate &trait_reference; TyTy::TypeBoundPredicateItem resolved_trait_item; - HIR::ImplBlock *parent; + HIR::ImplBlock &parent; TyTy::BaseType *self; std::vector<TyTy::SubstitutionParamMapping> substitutions; TyTy::RegionConstraints region_constraints; diff --git a/gcc/rust/typecheck/rust-hir-type-check-item.cc b/gcc/rust/typecheck/rust-hir-type-check-item.cc index 68e2069..aaa04af 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-item.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-item.cc @@ -17,6 +17,7 @@ // <http://www.gnu.org/licenses/>. #include "rust-hir-type-check-item.h" +#include "optional.h" #include "rust-canonical-path.h" #include "rust-diagnostics.h" #include "rust-hir-type-check-enumitem.h" @@ -32,6 +33,9 @@ #include "rust-type-util.h" #include "rust-tyty-variance-analysis.h" +// for flag_name_resolution_2_0 +#include "options.h" + namespace Rust { namespace Resolver { @@ -147,7 +151,7 @@ void TypeCheckItem::visit (HIR::TypeAlias &alias) { TyTy::BaseType *actual_type - = TypeCheckType::Resolve (alias.get_type_aliased ().get ()); + = TypeCheckType::Resolve (alias.get_type_aliased ()); context->insert_type (alias.get_mappings (), actual_type); @@ -179,7 +183,7 @@ TypeCheckItem::visit (HIR::TupleStruct &struct_decl) for (auto &field : struct_decl.get_fields ()) { TyTy::BaseType *field_type - = TypeCheckType::Resolve (field.get_field_type ().get ()); + = TypeCheckType::Resolve (field.get_field_type ()); auto *ty_field = new TyTy::StructFieldType (field.get_mappings ().get_hirid (), std::to_string (idx), field_type, @@ -196,7 +200,7 @@ TypeCheckItem::visit (HIR::TupleStruct &struct_decl) // FIXME: HACK: ARTHUR: Disgusting if (flag_name_resolution_2_0) { - auto nr_ctx + auto &nr_ctx = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); path = nr_ctx.values @@ -219,7 +223,7 @@ TypeCheckItem::visit (HIR::TupleStruct &struct_decl) new TyTy::VariantDef (struct_decl.get_mappings ().get_hirid (), struct_decl.get_mappings ().get_defid (), struct_decl.get_identifier ().as_string (), ident, - TyTy::VariantDef::VariantType::TUPLE, nullptr, + TyTy::VariantDef::VariantType::TUPLE, tl::nullopt, std::move (fields))); // Process #[repr(X)] attribute, if any @@ -228,7 +232,9 @@ TypeCheckItem::visit (HIR::TupleStruct &struct_decl) = parse_repr_options (attrs, struct_decl.get_locus ()); auto *type = new TyTy::ADTType ( - struct_decl.get_mappings ().get_hirid (), mappings.get_next_hir_id (), + struct_decl.get_mappings ().get_defid (), + struct_decl.get_mappings ().get_hirid (), + struct_decl.get_mappings ().get_hirid (), struct_decl.get_identifier ().as_string (), ident, TyTy::ADTType::ADTKind::TUPLE_STRUCT, std::move (variants), std::move (substitutions), repr, @@ -261,7 +267,7 @@ TypeCheckItem::visit (HIR::StructStruct &struct_decl) for (auto &field : struct_decl.get_fields ()) { TyTy::BaseType *field_type - = TypeCheckType::Resolve (field.get_field_type ().get ()); + = TypeCheckType::Resolve (field.get_field_type ()); auto *ty_field = new TyTy::StructFieldType (field.get_mappings ().get_hirid (), field.get_field_name ().as_string (), @@ -275,7 +281,7 @@ TypeCheckItem::visit (HIR::StructStruct &struct_decl) // FIXME: HACK: ARTHUR: Disgusting if (flag_name_resolution_2_0) { - auto nr_ctx + auto &nr_ctx = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); auto canonical_path = nr_ctx.types.to_canonical_path ( struct_decl.get_mappings ().get_nodeid ()); @@ -300,7 +306,7 @@ TypeCheckItem::visit (HIR::StructStruct &struct_decl) new TyTy::VariantDef (struct_decl.get_mappings ().get_hirid (), struct_decl.get_mappings ().get_defid (), struct_decl.get_identifier ().as_string (), ident, - TyTy::VariantDef::VariantType::STRUCT, nullptr, + TyTy::VariantDef::VariantType::STRUCT, tl::nullopt, std::move (fields))); // Process #[repr(X)] attribute, if any @@ -309,7 +315,9 @@ TypeCheckItem::visit (HIR::StructStruct &struct_decl) = parse_repr_options (attrs, struct_decl.get_locus ()); auto *type = new TyTy::ADTType ( - struct_decl.get_mappings ().get_hirid (), mappings.get_next_hir_id (), + struct_decl.get_mappings ().get_defid (), + struct_decl.get_mappings ().get_hirid (), + struct_decl.get_mappings ().get_hirid (), struct_decl.get_identifier ().as_string (), ident, TyTy::ADTType::ADTKind::STRUCT_STRUCT, std::move (variants), std::move (substitutions), repr, @@ -331,29 +339,63 @@ TypeCheckItem::visit (HIR::Enum &enum_decl) if (enum_decl.has_generics ()) resolve_generic_params (enum_decl.get_generic_params (), substitutions); + // Process #[repr(X)] attribute, if any + const AST::AttrVec &attrs = enum_decl.get_outer_attrs (); + TyTy::ADTType::ReprOptions repr + = parse_repr_options (attrs, enum_decl.get_locus ()); + std::vector<TyTy::VariantDef *> variants; int64_t discriminant_value = 0; for (auto &variant : enum_decl.get_variants ()) { TyTy::VariantDef *field_type - = TypeCheckEnumItem::Resolve (variant.get (), discriminant_value); + = TypeCheckEnumItem::Resolve (*variant, discriminant_value); discriminant_value++; variants.push_back (field_type); } + // Check for zero-variant enum compatibility + if (enum_decl.is_zero_variant ()) + { + if (repr.repr_kind == TyTy::ADTType::ReprKind::INT + || repr.repr_kind == TyTy::ADTType::ReprKind::C) + { + rust_error_at (enum_decl.get_locus (), + "unsupported representation for zero-variant enum"); + return; + } + } + // get the path - auto canonical_path - = mappings.lookup_canonical_path (enum_decl.get_mappings ().get_nodeid ()); + tl::optional<CanonicalPath> canonical_path; + + if (flag_name_resolution_2_0) + { + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); + + canonical_path = nr_ctx.types.to_canonical_path ( + enum_decl.get_mappings ().get_nodeid ()); + } + else + { + canonical_path = mappings.lookup_canonical_path ( + enum_decl.get_mappings ().get_nodeid ()); + } + + rust_assert (canonical_path.has_value ()); + RustIdent ident{*canonical_path, enum_decl.get_locus ()}; // multi variant ADT auto *type - = new TyTy::ADTType (enum_decl.get_mappings ().get_hirid (), - mappings.get_next_hir_id (), + = new TyTy::ADTType (enum_decl.get_mappings ().get_defid (), + enum_decl.get_mappings ().get_hirid (), + enum_decl.get_mappings ().get_hirid (), enum_decl.get_identifier ().as_string (), ident, TyTy::ADTType::ADTKind::ENUM, std::move (variants), - std::move (substitutions)); + std::move (substitutions), repr); context->insert_type (enum_decl.get_mappings (), type); infered = type; @@ -379,7 +421,7 @@ TypeCheckItem::visit (HIR::Union &union_decl) for (auto &variant : union_decl.get_variants ()) { TyTy::BaseType *variant_type - = TypeCheckType::Resolve (variant.get_field_type ().get ()); + = TypeCheckType::Resolve (variant.get_field_type ()); auto *ty_variant = new TyTy::StructFieldType (variant.get_mappings ().get_hirid (), variant.get_field_name ().as_string (), @@ -390,8 +432,24 @@ TypeCheckItem::visit (HIR::Union &union_decl) } // get the path - auto canonical_path - = mappings.lookup_canonical_path (union_decl.get_mappings ().get_nodeid ()); + tl::optional<CanonicalPath> canonical_path; + + if (flag_name_resolution_2_0) + { + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); + + canonical_path = nr_ctx.types.to_canonical_path ( + union_decl.get_mappings ().get_nodeid ()); + } + else + { + canonical_path = mappings.lookup_canonical_path ( + union_decl.get_mappings ().get_nodeid ()); + } + + rust_assert (canonical_path.has_value ()); + RustIdent ident{*canonical_path, union_decl.get_locus ()}; // there is only a single variant @@ -400,12 +458,13 @@ TypeCheckItem::visit (HIR::Union &union_decl) new TyTy::VariantDef (union_decl.get_mappings ().get_hirid (), union_decl.get_mappings ().get_defid (), union_decl.get_identifier ().as_string (), ident, - TyTy::VariantDef::VariantType::STRUCT, nullptr, + TyTy::VariantDef::VariantType::STRUCT, tl::nullopt, std::move (fields))); auto *type - = new TyTy::ADTType (union_decl.get_mappings ().get_hirid (), - mappings.get_next_hir_id (), + = new TyTy::ADTType (union_decl.get_mappings ().get_defid (), + union_decl.get_mappings ().get_hirid (), + union_decl.get_mappings ().get_hirid (), union_decl.get_identifier ().as_string (), ident, TyTy::ADTType::ADTKind::UNION, std::move (variants), std::move (substitutions)); @@ -419,14 +478,14 @@ TypeCheckItem::visit (HIR::Union &union_decl) void TypeCheckItem::visit (HIR::StaticItem &var) { - TyTy::BaseType *type = TypeCheckType::Resolve (var.get_type ().get ()); - TyTy::BaseType *expr_type = TypeCheckExpr::Resolve (var.get_expr ().get ()); + TyTy::BaseType *type = TypeCheckType::Resolve (var.get_type ()); + TyTy::BaseType *expr_type = TypeCheckExpr::Resolve (var.get_expr ()); TyTy::BaseType *unified = coercion_site (var.get_mappings ().get_hirid (), - TyTy::TyWithLocation (type, var.get_type ()->get_locus ()), + TyTy::TyWithLocation (type, var.get_type ().get_locus ()), TyTy::TyWithLocation (expr_type, - var.get_expr ()->get_locus ()), + var.get_expr ().get_locus ()), var.get_locus ()); context->insert_type (var.get_mappings (), unified); infered = unified; @@ -435,14 +494,13 @@ TypeCheckItem::visit (HIR::StaticItem &var) void TypeCheckItem::visit (HIR::ConstantItem &constant) { - TyTy::BaseType *type = TypeCheckType::Resolve (constant.get_type ().get ()); - TyTy::BaseType *expr_type - = TypeCheckExpr::Resolve (constant.get_expr ().get ()); + TyTy::BaseType *type = TypeCheckType::Resolve (constant.get_type ()); + TyTy::BaseType *expr_type = TypeCheckExpr::Resolve (constant.get_expr ()); TyTy::BaseType *unified = unify_site ( constant.get_mappings ().get_hirid (), - TyTy::TyWithLocation (type, constant.get_type ()->get_locus ()), - TyTy::TyWithLocation (expr_type, constant.get_expr ()->get_locus ()), + TyTy::TyWithLocation (type, constant.get_type ().get_locus ()), + TyTy::TyWithLocation (expr_type, constant.get_expr ().get_locus ()), constant.get_locus ()); context->insert_type (constant.get_mappings (), unified); infered = unified; @@ -453,6 +511,15 @@ TypeCheckItem::visit (HIR::ImplBlock &impl_block) { auto binder_pin = context->push_clean_lifetime_resolver (true); + TraitReference *trait_reference = &TraitReference::error_node (); + if (impl_block.has_trait_ref ()) + { + HIR::TypePath &ref = impl_block.get_trait_ref (); + trait_reference = TraitResolver::Resolve (ref); + if (trait_reference->is_error ()) + return; + } + bool failed_flag = false; auto result = resolve_impl_block_substitutions (impl_block, failed_flag); if (failed_flag) @@ -469,12 +536,11 @@ TypeCheckItem::visit (HIR::ImplBlock &impl_block) // resolve each impl_item for (auto &impl_item : impl_block.get_impl_items ()) { - TypeCheckImplItem::Resolve (&impl_block, impl_item.get (), self, - substitutions); + TypeCheckImplItem::Resolve (impl_block, *impl_item, self, substitutions); } // validate the impl items - validate_trait_impl_block (impl_block, self, substitutions); + validate_trait_impl_block (trait_reference, impl_block, self, substitutions); } TyTy::BaseType * @@ -494,7 +560,7 @@ TypeCheckItem::resolve_impl_item (HIR::ImplBlock &impl_block, TyTy::BaseType *self = resolve_impl_block_self (impl_block); - return TypeCheckImplItem::Resolve (&impl_block, &item, self, substitutions); + return TypeCheckImplItem::Resolve (impl_block, item, self, substitutions); } void @@ -514,12 +580,10 @@ TypeCheckItem::visit (HIR::Function &function) TyTy::BaseType *ret_type = nullptr; if (!function.has_function_return_type ()) - ret_type - = TyTy::TupleType::get_unit_type (function.get_mappings ().get_hirid ()); + ret_type = TyTy::TupleType::get_unit_type (); else { - auto resolved - = TypeCheckType::Resolve (function.get_return_type ().get ()); + auto resolved = TypeCheckType::Resolve (function.get_return_type ()); if (resolved->get_kind () == TyTy::TypeKind::ERROR) { rust_error_at (function.get_locus (), @@ -529,18 +593,18 @@ TypeCheckItem::visit (HIR::Function &function) ret_type = resolved->clone (); ret_type->set_ref ( - function.get_return_type ()->get_mappings ().get_hirid ()); + function.get_return_type ().get_mappings ().get_hirid ()); } - std::vector<std::pair<HIR::Pattern *, TyTy::BaseType *>> params; + std::vector<TyTy::FnParam> params; for (auto ¶m : function.get_function_params ()) { // get the name as well required for later on - auto param_tyty = TypeCheckType::Resolve (param.get_type ().get ()); - params.emplace_back (param.get_param_name ().get (), param_tyty); - + auto param_tyty = TypeCheckType::Resolve (param.get_type ()); context->insert_type (param.get_mappings (), param_tyty); - TypeCheckPattern::Resolve (param.get_param_name ().get (), param_tyty); + TypeCheckPattern::Resolve (param.get_param_name (), param_tyty); + params.push_back ( + TyTy::FnParam (param.get_param_name ().clone_pattern (), param_tyty)); } auto path = CanonicalPath::create_empty (); @@ -548,7 +612,7 @@ TypeCheckItem::visit (HIR::Function &function) // FIXME: HACK: ARTHUR: Disgusting if (flag_name_resolution_2_0) { - auto nr_ctx + auto &nr_ctx = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); auto canonical_path = nr_ctx.values.to_canonical_path ( function.get_mappings ().get_nodeid ()); @@ -583,16 +647,47 @@ TypeCheckItem::visit (HIR::Function &function) expected_ret_tyty); context->switch_to_fn_body (); - auto block_expr_ty - = TypeCheckExpr::Resolve (function.get_definition ().get ()); + auto block_expr_ty = TypeCheckExpr::Resolve (function.get_definition ()); + + // emit check for + // error[E0121]: the type placeholder `_` is not allowed within types on item + const auto placeholder = ret_type->contains_infer (); + if (placeholder != nullptr && function.has_return_type ()) + { + // FIXME + // this will be a great place for the Default Hir Visitor we want to + // grab the locations of the placeholders (HIR::InferredType) their + // location, for now maybe we can use their hirid to lookup the location + location_t placeholder_locus + = mappings.lookup_location (placeholder->get_ref ()); + location_t type_locus = function.get_return_type ().get_locus (); + rich_location r (line_table, placeholder_locus); + + bool have_expected_type + = block_expr_ty != nullptr && !block_expr_ty->is<TyTy::ErrorType> (); + if (!have_expected_type) + { + r.add_range (type_locus); + } + else + { + std::string fixit + = "replace with the correct type " + block_expr_ty->get_name (); + r.add_fixit_replace (type_locus, fixit.c_str ()); + } + + rust_error_at (r, ErrorCode::E0121, + "the type placeholder %<_%> is not allowed within types " + "on item signatures"); + } location_t fn_return_locus = function.has_function_return_type () - ? function.get_return_type ()->get_locus () + ? function.get_return_type ().get_locus () : function.get_locus (); - coercion_site (function.get_definition ()->get_mappings ().get_hirid (), + coercion_site (function.get_definition ().get_mappings ().get_hirid (), TyTy::TyWithLocation (expected_ret_tyty, fn_return_locus), TyTy::TyWithLocation (block_expr_ty), - function.get_definition ()->get_locus ()); + function.get_definition ().get_locus ()); context->pop_return_type (); @@ -646,7 +741,7 @@ TypeCheckItem::visit (HIR::ExternBlock &extern_block) { for (auto &item : extern_block.get_extern_items ()) { - TypeCheckTopLevelExternItem::Resolve (item.get (), extern_block); + TypeCheckTopLevelExternItem::Resolve (*item, extern_block); } } @@ -668,17 +763,25 @@ TypeCheckItem::resolve_impl_block_substitutions (HIR::ImplBlock &impl_block, TraitReference *trait_reference = &TraitReference::error_node (); if (impl_block.has_trait_ref ()) { - std::unique_ptr<HIR::TypePath> &ref = impl_block.get_trait_ref (); - trait_reference = TraitResolver::Resolve (*ref); + auto &ref = impl_block.get_trait_ref (); + trait_reference = TraitResolver::Resolve (ref); rust_assert (!trait_reference->is_error ()); // we don't error out here see: gcc/testsuite/rust/compile/traits2.rs // for example - specified_bound - = get_predicate_from_bound (*ref, impl_block.get_type ().get ()); + specified_bound = get_predicate_from_bound (ref, impl_block.get_type (), + impl_block.get_polarity ()); } - TyTy::BaseType *self = TypeCheckType::Resolve (impl_block.get_type ().get ()); + TyTy::BaseType *self = TypeCheckType::Resolve (impl_block.get_type ()); + if (self->is<TyTy::ErrorType> ()) + { + // we cannot check for unconstrained type arguments when the Self type is + // not resolved it will just add extra errors that dont help as well as + // the case where this could just be a recursive type query that should + // fail and will work later on anyway + return {substitutions, region_constraints}; + } // inherit the bounds if (!specified_bound.is_error ()) @@ -698,21 +801,28 @@ TypeCheckItem::resolve_impl_block_substitutions (HIR::ImplBlock &impl_block, void TypeCheckItem::validate_trait_impl_block ( - HIR::ImplBlock &impl_block, TyTy::BaseType *self, + TraitReference *trait_reference, HIR::ImplBlock &impl_block, + TyTy::BaseType *self, std::vector<TyTy::SubstitutionParamMapping> &substitutions) { auto specified_bound = TyTy::TypeBoundPredicate::error (); - TraitReference *trait_reference = &TraitReference::error_node (); if (impl_block.has_trait_ref ()) { - std::unique_ptr<HIR::TypePath> &ref = impl_block.get_trait_ref (); - trait_reference = TraitResolver::Resolve (*ref); - rust_assert (!trait_reference->is_error ()); + auto &ref = impl_block.get_trait_ref (); + trait_reference = TraitResolver::Resolve (ref); + if (trait_reference->is_error ()) + return; // we don't error out here see: gcc/testsuite/rust/compile/traits2.rs // for example - specified_bound - = get_predicate_from_bound (*ref, impl_block.get_type ().get ()); + specified_bound = get_predicate_from_bound (ref, impl_block.get_type (), + impl_block.get_polarity ()); + + // need to check that if this specified bound has super traits does this + // Self + // implement them? + specified_bound.validate_type_implements_super_traits ( + *self, impl_block.get_type (), impl_block.get_trait_ref ()); } bool is_trait_impl_block = !trait_reference->is_error (); @@ -722,8 +832,7 @@ TypeCheckItem::validate_trait_impl_block ( if (!specified_bound.is_error ()) { auto trait_item_ref - = TypeCheckImplItemWithTrait::Resolve (&impl_block, - impl_item.get (), self, + = TypeCheckImplItemWithTrait::Resolve (impl_block, *impl_item, self, specified_bound, substitutions); if (!trait_item_ref.is_error ()) @@ -734,7 +843,8 @@ TypeCheckItem::validate_trait_impl_block ( bool impl_block_missing_trait_items = !specified_bound.is_error () && trait_reference->size () != trait_item_refs.size (); - if (impl_block_missing_trait_items) + if (impl_block_missing_trait_items + && impl_block.get_polarity () == BoundPolarity::RegularBound) { // filter the missing impl_items std::vector<std::reference_wrapper<const TraitItemReference>> @@ -795,7 +905,7 @@ TypeCheckItem::validate_trait_impl_block ( TyTy::BaseType * TypeCheckItem::resolve_impl_block_self (HIR::ImplBlock &impl_block) { - return TypeCheckType::Resolve (impl_block.get_type ().get ()); + return TypeCheckType::Resolve (impl_block.get_type ()); } } // namespace Resolver diff --git a/gcc/rust/typecheck/rust-hir-type-check-item.h b/gcc/rust/typecheck/rust-hir-type-check-item.h index c5b94db..56832e7 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-item.h +++ b/gcc/rust/typecheck/rust-hir-type-check-item.h @@ -63,7 +63,8 @@ protected: bool &failure_flag); void validate_trait_impl_block ( - HIR::ImplBlock &impl_block, TyTy::BaseType *self, + TraitReference *trait_reference, HIR::ImplBlock &impl_block, + TyTy::BaseType *self, std::vector<TyTy::SubstitutionParamMapping> &substitutions); TyTy::BaseType *resolve_impl_item (HIR::ImplBlock &impl_block, diff --git a/gcc/rust/typecheck/rust-hir-type-check-path.cc b/gcc/rust/typecheck/rust-hir-type-check-path.cc index c655209..5662da5 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-path.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-path.cc @@ -16,6 +16,9 @@ // along with GCC; see the file COPYING3. If not see // <http://www.gnu.org/licenses/>. +#include "rust-diagnostics.h" +#include "rust-hir-map.h" +#include "rust-hir-path.h" #include "rust-hir-type-check-expr.h" #include "rust-hir-type-check-type.h" #include "rust-hir-type-check-item.h" @@ -24,6 +27,7 @@ #include "rust-hir-path-probe.h" #include "rust-type-util.h" #include "rust-hir-type-bounds.h" +#include "rust-hir-item.h" #include "rust-session-manager.h" #include "rust-immutable-name-resolution-context.h" @@ -34,8 +38,7 @@ void TypeCheckExpr::visit (HIR::QualifiedPathInExpression &expr) { HIR::QualifiedPathType qual_path_type = expr.get_path_type (); - TyTy::BaseType *root - = TypeCheckType::Resolve (qual_path_type.get_type ().get ()); + TyTy::BaseType *root = TypeCheckType::Resolve (qual_path_type.get_type ()); if (root->get_kind () == TyTy::TypeKind::ERROR) return; @@ -48,8 +51,8 @@ TypeCheckExpr::visit (HIR::QualifiedPathInExpression &expr) } // Resolve the trait now - std::unique_ptr<HIR::TypePath> &trait_path_ref = qual_path_type.get_trait (); - TraitReference *trait_ref = TraitResolver::Resolve (*trait_path_ref.get ()); + HIR::TypePath &trait_path_ref = qual_path_type.get_trait (); + TraitReference *trait_ref = TraitResolver::Resolve (trait_path_ref); if (trait_ref->is_error ()) return; @@ -64,8 +67,7 @@ TypeCheckExpr::visit (HIR::QualifiedPathInExpression &expr) // get the predicate for the bound auto specified_bound - = get_predicate_from_bound (*trait_path_ref.get (), - qual_path_type.get_type ().get ()); + = get_predicate_from_bound (trait_path_ref, qual_path_type.get_type ()); if (specified_bound.is_error ()) return; @@ -155,9 +157,20 @@ TypeCheckExpr::visit (HIR::QualifiedPathInExpression &expr) bool fully_resolved = expr.get_segments ().size () <= 1; if (fully_resolved) { - resolver->insert_resolved_name (expr.get_mappings ().get_nodeid (), - root_resolved_node_id); - context->insert_receiver (expr.get_mappings ().get_hirid (), root); + if (flag_name_resolution_2_0) + { + auto &nr_ctx = const_cast<Resolver2_0::NameResolutionContext &> ( + Resolver2_0::ImmutableNameResolutionContext::get ().resolver ()); + + nr_ctx.map_usage (Resolver2_0::Usage ( + expr.get_mappings ().get_nodeid ()), + Resolver2_0::Definition (root_resolved_node_id)); + } + else + { + resolver->insert_resolved_name (expr.get_mappings ().get_nodeid (), + root_resolved_node_id); + } return; } @@ -169,20 +182,72 @@ void TypeCheckExpr::visit (HIR::PathInExpression &expr) { NodeId resolved_node_id = UNKNOWN_NODEID; - size_t offset = -1; - TyTy::BaseType *tyseg = resolve_root_path (expr, &offset, &resolved_node_id); - if (tyseg->get_kind () == TyTy::TypeKind::ERROR) - return; - - bool fully_resolved = offset == expr.get_segments ().size (); - if (fully_resolved) + if (expr.is_lang_item ()) { - infered = tyseg; - return; + auto lookup + = Analysis::Mappings::get ().get_lang_item_node (expr.get_lang_item ()); + auto hir_id = mappings.lookup_node_to_hir (lookup); + + // We can type resolve the path in expression easily as it is a lang + // item path, but we still need to setup the various generics and + // substitutions + + // FIXME: We probably need to check *if* the type needs substitutions + // or not + if (LangItem::IsEnumVariant (expr.get_lang_item ())) + { + std::pair<HIR::Enum *, HIR::EnumItem *> enum_item_lookup + = mappings.lookup_hir_enumitem (*hir_id); + bool enum_item_ok = enum_item_lookup.first != nullptr + && enum_item_lookup.second != nullptr; + rust_assert (enum_item_ok); + + HirId variant_id + = enum_item_lookup.second->get_mappings ().get_hirid (); + + HIR::EnumItem *enum_item = enum_item_lookup.second; + resolved_node_id = enum_item->get_mappings ().get_nodeid (); + + // insert the id of the variant we are resolved to + context->insert_variant_definition (expr.get_mappings ().get_hirid (), + variant_id); + + query_type (variant_id, &infered); + infered = SubstMapper::InferSubst (infered, expr.get_locus ()); + } + else + { + TyTy::BaseType *resolved = nullptr; + context->lookup_type (*hir_id, &resolved); + + rust_assert (resolved); + + query_type (*hir_id, &infered); + + infered = SubstMapper::InferSubst (resolved, expr.get_locus ()); + } + + // FIXME: also we probably need to insert resolved types in the name + // resolver here } + else + { + size_t offset = -1; + TyTy::BaseType *tyseg + = resolve_root_path (expr, &offset, &resolved_node_id); + if (tyseg->get_kind () == TyTy::TypeKind::ERROR) + return; - resolve_segments (resolved_node_id, expr.get_segments (), offset, tyseg, - expr.get_mappings (), expr.get_locus ()); + bool fully_resolved = offset == expr.get_segments ().size (); + if (fully_resolved) + { + infered = tyseg; + return; + } + + resolve_segments (resolved_node_id, expr.get_segments (), offset, tyseg, + expr.get_mappings (), expr.get_locus ()); + } } TyTy::BaseType * @@ -204,12 +269,13 @@ TypeCheckExpr::resolve_root_path (HIR::PathInExpression &expr, size_t *offset, if (flag_name_resolution_2_0) { - auto nr_ctx + auto &nr_ctx = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); // assign the ref_node_id if we've found something - nr_ctx.lookup (expr.get_mappings ().get_nodeid ()) - .map ([&ref_node_id] (NodeId resolved) { ref_node_id = resolved; }); + nr_ctx.lookup (ast_node_id).map ([&ref_node_id] (NodeId resolved) { + ref_node_id = resolved; + }); } else if (!resolver->lookup_resolved_name (ast_node_id, &ref_node_id)) resolver->lookup_resolved_type (ast_node_id, &ref_node_id); @@ -245,6 +311,9 @@ TypeCheckExpr::resolve_root_path (HIR::PathInExpression &expr, size_t *offset, auto seg_is_module = mappings.lookup_module (ref).has_value (); auto seg_is_crate = mappings.is_local_hirid_crate (ref); + auto seg_is_pattern = mappings.lookup_hir_pattern (ref).has_value (); + auto seg_is_self = is_root && !have_more_segments + && seg.get_segment ().as_string () == "self"; if (seg_is_module || seg_is_crate) { // A::B::C::this_is_a_module::D::E::F @@ -267,7 +336,7 @@ TypeCheckExpr::resolve_root_path (HIR::PathInExpression &expr, size_t *offset, TyTy::BaseType *lookup = nullptr; if (!query_type (ref, &lookup)) { - if (is_root) + if (is_root || root_tyty == nullptr) { rust_error_at (expr.get_locus (), ErrorCode::E0425, "cannot find value %qs in this scope", @@ -321,7 +390,8 @@ TypeCheckExpr::resolve_root_path (HIR::PathInExpression &expr, size_t *offset, if (lookup->get_kind () == TyTy::TypeKind::ERROR) return new TyTy::ErrorType (expr.get_mappings ().get_hirid ()); } - else if (lookup->needs_generic_substitutions ()) + else if (lookup->needs_generic_substitutions () && !seg_is_pattern + && !seg_is_self) { lookup = SubstMapper::InferSubst (lookup, expr.get_locus ()); } @@ -343,12 +413,13 @@ TypeCheckExpr::resolve_segments (NodeId root_resolved_node_id, { NodeId resolved_node_id = root_resolved_node_id; TyTy::BaseType *prev_segment = tyseg; - bool reciever_is_generic = prev_segment->get_kind () == TyTy::TypeKind::PARAM; + bool receiver_is_generic = prev_segment->get_kind () == TyTy::TypeKind::PARAM; + bool receiver_is_dyn = prev_segment->get_kind () == TyTy::TypeKind::DYNAMIC; for (size_t i = offset; i < segments.size (); i++) { HIR::PathExprSegment &seg = segments.at (i); - bool probe_impls = !reciever_is_generic; + bool probe_impls = !receiver_is_generic; // probe the path is done in two parts one where we search impls if no // candidate is found then we search extensions from traits @@ -423,7 +494,7 @@ TypeCheckExpr::resolve_segments (NodeId root_resolved_node_id, } } - if (associated_impl_block != nullptr) + if (associated_impl_block != nullptr && !receiver_is_dyn) { // associated types HirId impl_block_id @@ -456,7 +527,7 @@ TypeCheckExpr::resolve_segments (NodeId root_resolved_node_id, { // we need to setup with apropriate bounds HIR::TypePath &bound_path - = *associated->get_impl_block ()->get_trait_ref ().get (); + = associated->get_impl_block ()->get_trait_ref (); const auto &trait_ref = *TraitResolver::Resolve (bound_path); rust_assert (!trait_ref.is_error ()); @@ -464,8 +535,8 @@ TypeCheckExpr::resolve_segments (NodeId root_resolved_node_id, = impl_block_ty->lookup_predicate (trait_ref.get_defid ()); if (!predicate.is_error ()) impl_block_ty - = associated->setup_associated_types (prev_segment, - predicate); + = associated->setup_associated_types (prev_segment, predicate, + nullptr, false); } } @@ -480,7 +551,7 @@ TypeCheckExpr::resolve_segments (NodeId root_resolved_node_id, if (tyseg->get_kind () == TyTy::TypeKind::ERROR) return; } - else if (tyseg->needs_generic_substitutions () && !reciever_is_generic) + else if (tyseg->needs_generic_substitutions () && !receiver_is_generic) { location_t locus = seg.get_locus (); tyseg = SubstMapper::InferSubst (tyseg, locus); @@ -490,18 +561,17 @@ TypeCheckExpr::resolve_segments (NodeId root_resolved_node_id, } rust_assert (resolved_node_id != UNKNOWN_NODEID); - if (tyseg->needs_generic_substitutions () && !reciever_is_generic) + if (flag_name_resolution_2_0) { - location_t locus = segments.back ().get_locus (); - tyseg = SubstMapper::InferSubst (tyseg, locus); - if (tyseg->get_kind () == TyTy::TypeKind::ERROR) - return; - } - - context->insert_receiver (expr_mappings.get_hirid (), prev_segment); + auto &nr_ctx = const_cast<Resolver2_0::NameResolutionContext &> ( + Resolver2_0::ImmutableNameResolutionContext::get ().resolver ()); + nr_ctx.map_usage (Resolver2_0::Usage (expr_mappings.get_nodeid ()), + Resolver2_0::Definition (resolved_node_id)); + } // name scope first - if (resolver->get_name_scope ().decl_was_declared_here (resolved_node_id)) + else if (resolver->get_name_scope ().decl_was_declared_here ( + resolved_node_id)) { resolver->insert_resolved_name (expr_mappings.get_nodeid (), resolved_node_id); diff --git a/gcc/rust/typecheck/rust-hir-type-check-pattern.cc b/gcc/rust/typecheck/rust-hir-type-check-pattern.cc index c469f60..bd13f7a 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-pattern.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-pattern.cc @@ -17,8 +17,13 @@ // <http://www.gnu.org/licenses/>. #include "rust-hir-type-check-pattern.h" +#include "rust-hir-pattern.h" #include "rust-hir-type-check-expr.h" #include "rust-type-util.h" +#include "rust-immutable-name-resolution-context.h" + +// for flag_name_resolution_2_0 +#include "options.h" namespace Rust { namespace Resolver { @@ -28,28 +33,135 @@ TypeCheckPattern::TypeCheckPattern (TyTy::BaseType *parent) {} TyTy::BaseType * -TypeCheckPattern::Resolve (HIR::Pattern *pattern, TyTy::BaseType *parent) +TypeCheckPattern::Resolve (HIR::Pattern &pattern, TyTy::BaseType *parent) { TypeCheckPattern resolver (parent); - pattern->accept_vis (resolver); + pattern.accept_vis (resolver); if (resolver.infered == nullptr) - return new TyTy::ErrorType (pattern->get_mappings ().get_hirid ()); + return new TyTy::ErrorType (pattern.get_mappings ().get_hirid ()); - resolver.context->insert_type (pattern->get_mappings (), resolver.infered); + resolver.context->insert_type (pattern.get_mappings (), resolver.infered); return resolver.infered; } void TypeCheckPattern::visit (HIR::PathInExpression &pattern) { - infered = TypeCheckExpr::Resolve (&pattern); + // Pattern must be enum variants, sturcts, constants, or associated constansts + TyTy::BaseType *pattern_ty = TypeCheckExpr::Resolve (pattern); + + NodeId ref_node_id = UNKNOWN_NODEID; + bool maybe_item = false; + + if (flag_name_resolution_2_0) + { + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); + + if (auto id = nr_ctx.lookup (pattern.get_mappings ().get_nodeid ())) + { + ref_node_id = *id; + maybe_item = true; + } + } + else + { + maybe_item |= resolver->lookup_resolved_name ( + pattern.get_mappings ().get_nodeid (), &ref_node_id); + maybe_item |= resolver->lookup_resolved_type ( + pattern.get_mappings ().get_nodeid (), &ref_node_id); + } + + bool path_is_const_item = false; + + if (maybe_item) + { + tl::optional<HirId> definition_id + = mappings.lookup_node_to_hir (ref_node_id); + rust_assert (definition_id.has_value ()); + HirId def_id = definition_id.value (); + + tl::optional<HIR::Item *> hir_item = mappings.lookup_hir_item (def_id); + // If the path refrerences an item, it must be constants or structs. + if (hir_item.has_value ()) + { + HIR::Item *item = hir_item.value (); + if (item->get_item_kind () == HIR::Item::ItemKind::Constant) + { + path_is_const_item = true; + } + else if (item->get_item_kind () != HIR::Item::ItemKind::Struct) + { + HIR::Item *item = hir_item.value (); + std::string item_kind + = HIR::Item::item_kind_string (item->get_item_kind ()); + + std::string path_buf; + for (size_t i = 0; i < pattern.get_segments ().size (); i++) + { + HIR::PathExprSegment &seg = pattern.get_segments ().at (i); + path_buf += seg.as_string (); + if (i != pattern.get_segments ().size () - 1) + path_buf += "::"; + } + + rich_location rich_locus ( + line_table, pattern.get_final_segment ().get_locus ()); + rich_locus.add_fixit_replace ( + "not a unit struct, unit variant or constant"); + rust_error_at (rich_locus, ErrorCode::E0532, + "expected unit struct, unit variant or constant, " + "found %s %<%s%>", + item_kind.c_str (), path_buf.c_str ()); + return; + } + } + } + + // If the path is a constructor, it must be a unit struct or unit variants. + if (!path_is_const_item && pattern_ty->get_kind () == TyTy::TypeKind::ADT) + { + TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (pattern_ty); + rust_assert (adt->get_variants ().size () > 0); + + TyTy::VariantDef *variant = adt->get_variants ().at (0); + if (adt->is_enum ()) + { + HirId variant_id = UNKNOWN_HIRID; + bool ok = context->lookup_variant_definition ( + pattern.get_mappings ().get_hirid (), &variant_id); + rust_assert (ok); + + ok = adt->lookup_variant_by_id (variant_id, &variant); + rust_assert (ok); + } + + if (variant->get_variant_type () != TyTy::VariantDef::VariantType::NUM) + { + std::string variant_type = TyTy::VariantDef::variant_type_string ( + variant->get_variant_type ()); + + rich_location rich_locus (line_table, + pattern.get_final_segment ().get_locus ()); + rich_locus.add_fixit_replace ( + "not a unit struct, unit variant or constatnt"); + rust_error_at (rich_locus, ErrorCode::E0532, + "expected unit struct, unit variant or constant, " + "found %s variant %<%s::%s%>", + variant_type.c_str (), adt->get_name ().c_str (), + variant->get_identifier ().c_str ()); + return; + } + + infered = pattern_ty; + } } void TypeCheckPattern::visit (HIR::TupleStructPattern &pattern) { - TyTy::BaseType *pattern_ty = TypeCheckExpr::Resolve (&pattern.get_path ()); + TyTy::BaseType *pattern_ty = TypeCheckExpr::Resolve (pattern.get_path ()); if (pattern_ty->get_kind () != TyTy::TypeKind::ADT) { rust_error_at ( @@ -75,8 +187,8 @@ TypeCheckPattern::visit (HIR::TupleStructPattern &pattern) rust_assert (ok); } - // error[E0532]: expected tuple struct or tuple variant, found struct variant - // `Foo::D`, E0532 by rustc 1.49.0 , E0164 by rustc 1.71.0 + // error[E0532]: expected tuple struct or tuple variant, found struct + // variant `Foo::D`, E0532 by rustc 1.49.0 , E0164 by rustc 1.71.0 if (variant->get_variant_type () != TyTy::VariantDef::VariantType::TUPLE) { std::string variant_type @@ -98,8 +210,8 @@ TypeCheckPattern::visit (HIR::TupleStructPattern &pattern) // error[E0023]: this pattern has 0 fields, but the corresponding tuple // variant has 1 field - std::unique_ptr<HIR::TupleStructItems> &items = pattern.get_items (); - switch (items->get_item_type ()) + auto &items = pattern.get_items (); + switch (items.get_item_type ()) { case HIR::TupleStructItems::RANGED: { // TODO @@ -109,7 +221,7 @@ TypeCheckPattern::visit (HIR::TupleStructPattern &pattern) case HIR::TupleStructItems::MULTIPLE: { HIR::TupleStructItemsNoRange &items_no_range - = static_cast<HIR::TupleStructItemsNoRange &> (*items.get ()); + = static_cast<HIR::TupleStructItemsNoRange &> (items); if (items_no_range.get_patterns ().size () != variant->num_fields ()) { @@ -135,6 +247,7 @@ TypeCheckPattern::visit (HIR::TupleStructPattern &pattern) // setup the type on this pattern type context->insert_type (pattern->get_mappings (), fty); + TypeCheckPattern::Resolve (*pattern, fty); } } break; @@ -153,7 +266,7 @@ emit_invalid_field_error (location_t loc, Rust::TyTy::VariantDef *variant, void TypeCheckPattern::visit (HIR::StructPattern &pattern) { - TyTy::BaseType *pattern_ty = TypeCheckExpr::Resolve (&pattern.get_path ()); + TyTy::BaseType *pattern_ty = TypeCheckExpr::Resolve (pattern.get_path ()); if (pattern_ty->get_kind () != TyTy::TypeKind::ADT) { rust_error_at (pattern.get_locus (), @@ -164,7 +277,15 @@ TypeCheckPattern::visit (HIR::StructPattern &pattern) infered = pattern_ty; TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (infered); - rust_assert (adt->number_of_variants () > 0); + if (adt->number_of_variants () == 0) + { + HIR::PathInExpression &path = pattern.get_path (); + const AST::SimplePath &sp = path.as_simple_path (); + rust_error_at (pattern.get_locus (), ErrorCode::E0574, + "expected struct, variant or union type, found enum %qs", + sp.as_string ().c_str ()); + return; + } TyTy::VariantDef *variant = adt->get_variants ().at (0); if (adt->is_enum ()) @@ -172,14 +293,23 @@ TypeCheckPattern::visit (HIR::StructPattern &pattern) HirId variant_id = UNKNOWN_HIRID; bool ok = context->lookup_variant_definition ( pattern.get_path ().get_mappings ().get_hirid (), &variant_id); - rust_assert (ok); + if (!ok) + { + HIR::PathInExpression &path = pattern.get_path (); + const AST::SimplePath &sp = path.as_simple_path (); + rust_error_at ( + pattern.get_locus (), ErrorCode::E0574, + "expected struct, variant or union type, found enum %qs", + sp.as_string ().c_str ()); + return; + } ok = adt->lookup_variant_by_id (variant_id, &variant); rust_assert (ok); } - // error[E0532]: expected tuple struct or tuple variant, found struct variant - // `Foo::D` + // error[E0532]: expected tuple struct or tuple variant, found struct + // variant `Foo::D` if (variant->get_variant_type () != TyTy::VariantDef::VariantType::STRUCT) { std::string variant_type @@ -197,10 +327,6 @@ TypeCheckPattern::visit (HIR::StructPattern &pattern) return; } - // check the elements - // error[E0027]: pattern does not mention fields `x`, `y` - // error[E0026]: variant `Foo::D` does not have a field named `b` - std::vector<std::string> named_fields; auto &struct_pattern_elems = pattern.get_struct_pattern_elems (); for (auto &field : struct_pattern_elems.get_struct_pattern_fields ()) @@ -215,7 +341,7 @@ TypeCheckPattern::visit (HIR::StructPattern &pattern) case HIR::StructPatternField::ItemType::IDENT_PAT: { HIR::StructPatternFieldIdentPat &ident - = static_cast<HIR::StructPatternFieldIdentPat &> (*field.get ()); + = static_cast<HIR::StructPatternFieldIdentPat &> (*field); TyTy::StructFieldType *field = nullptr; if (!variant->lookup_field (ident.get_identifier ().as_string (), @@ -228,13 +354,13 @@ TypeCheckPattern::visit (HIR::StructPattern &pattern) named_fields.push_back (ident.get_identifier ().as_string ()); TyTy::BaseType *fty = field->get_field_type (); - TypeCheckPattern::Resolve (ident.get_pattern ().get (), fty); + TypeCheckPattern::Resolve (ident.get_pattern (), fty); } break; case HIR::StructPatternField::ItemType::IDENT: { HIR::StructPatternFieldIdent &ident - = static_cast<HIR::StructPatternFieldIdent &> (*field.get ()); + = static_cast<HIR::StructPatternFieldIdent &> (*field); TyTy::StructFieldType *field = nullptr; if (!variant->lookup_field (ident.get_identifier ().as_string (), @@ -254,31 +380,67 @@ TypeCheckPattern::visit (HIR::StructPattern &pattern) } } - if (named_fields.size () != variant->num_fields ()) + // check the elements + if (adt->is_union ()) { - std::map<std::string, bool> missing_names; - - // populate with all fields - for (auto &field : variant->get_fields ()) - missing_names[field->get_name ()] = true; + auto &struct_pattern_elems = pattern.get_struct_pattern_elems (); + if (struct_pattern_elems.get_struct_pattern_fields ().size () != 1) + rust_error_at (pattern.get_locus (), + "union patterns should have exactly one field"); - // then eliminate with named_fields - for (auto &named : named_fields) - missing_names.erase (named); - - // then get the list of missing names - size_t i = 0; - std::string missing_fields_str; - for (auto it = missing_names.begin (); it != missing_names.end (); it++) + else { - bool has_next = (i + 1) < missing_names.size (); - missing_fields_str += it->first + (has_next ? ", " : ""); - i++; + switch (struct_pattern_elems.get_struct_pattern_fields () + .at (0) + ->get_item_type ()) + { + case HIR::StructPatternField::ItemType::IDENT: + case HIR::StructPatternField::ItemType::IDENT_PAT: + break; + default: { + auto first_elem + = struct_pattern_elems.get_struct_pattern_fields () + .at (0) + ->as_string (); + rust_error_at (pattern.get_locus (), + "%qs cannot be used in union patterns", + first_elem.c_str ()); + } + } + } + } + else + { + // Expects enum struct or struct struct. + // error[E0027]: pattern does not mention fields `x`, `y` + // error[E0026]: variant `Foo::D` does not have a field named `b` + if (named_fields.size () != variant->num_fields ()) + { + std::map<std::string, bool> missing_names; + + // populate with all fields + for (auto &field : variant->get_fields ()) + missing_names[field->get_name ()] = true; + + // then eliminate with named_fields + for (auto &named : named_fields) + missing_names.erase (named); + + // then get the list of missing names + size_t i = 0; + std::string missing_fields_str; + for (auto it = missing_names.begin (); it != missing_names.end (); + it++) + { + bool has_next = (i + 1) < missing_names.size (); + missing_fields_str += it->first + (has_next ? ", " : ""); + i++; + } + + rust_error_at (pattern.get_locus (), ErrorCode::E0027, + "pattern does not mention fields %s", + missing_fields_str.c_str ()); } - - rust_error_at (pattern.get_locus (), ErrorCode::E0027, - "pattern does not mention fields %s", - missing_fields_str.c_str ()); } } @@ -295,12 +457,11 @@ void TypeCheckPattern::visit (HIR::TuplePattern &pattern) { std::unique_ptr<HIR::TuplePatternItems> items; - switch (pattern.get_items ()->get_item_type ()) + switch (pattern.get_items ().get_item_type ()) { case HIR::TuplePatternItems::ItemType::MULTIPLE: { - HIR::TuplePatternItemsMultiple &ref - = *static_cast<HIR::TuplePatternItemsMultiple *> ( - pattern.get_items ().get ()); + auto &ref = static_cast<HIR::TuplePatternItemsMultiple &> ( + pattern.get_items ()); auto resolved_parent = parent->destructure (); if (resolved_parent->get_kind () != TyTy::TUPLE) @@ -329,8 +490,7 @@ TypeCheckPattern::visit (HIR::TuplePattern &pattern) auto &p = patterns[i]; TyTy::BaseType *par_type = par.get_field (i); - TyTy::BaseType *elem - = TypeCheckPattern::Resolve (p.get (), par_type); + TyTy::BaseType *elem = TypeCheckPattern::Resolve (*p, par_type); pattern_elems.push_back (TyTy::TyVar (elem->get_ref ())); } infered = new TyTy::TupleType (pattern.get_mappings ().get_hirid (), @@ -376,9 +536,18 @@ TypeCheckPattern::visit (HIR::RangePattern &pattern) } void -TypeCheckPattern::visit (HIR::IdentifierPattern &) +TypeCheckPattern::visit (HIR::IdentifierPattern &pattern) { - infered = parent; + if (!pattern.get_is_ref ()) + { + infered = parent; + return; + } + + infered = new TyTy::ReferenceType (pattern.get_mappings ().get_hirid (), + TyTy::TyVar (parent->get_ref ()), + pattern.is_mut () ? Mutability::Mut + : Mutability::Imm); } void @@ -398,10 +567,10 @@ TypeCheckPattern::visit (HIR::ReferencePattern &pattern) return; } - TyTy::ReferenceType *ref_ty_ty = static_cast<TyTy::ReferenceType *> (parent); + auto &ref_ty_ty = static_cast<TyTy::ReferenceType &> (*parent); TyTy::BaseType *infered_base - = TypeCheckPattern::Resolve (pattern.get_referenced_pattern ().get (), - ref_ty_ty->get_base ()); + = TypeCheckPattern::Resolve (pattern.get_referenced_pattern (), + ref_ty_ty.get_base ()); infered = new TyTy::ReferenceType (pattern.get_mappings ().get_hirid (), TyTy::TyVar (infered_base->get_ref ()), pattern.is_mut () ? Mutability::Mut @@ -433,15 +602,14 @@ TypeCheckPattern::emit_pattern_size_error (const HIR::Pattern &pattern, TyTy::BaseType * TypeCheckPattern::typecheck_range_pattern_bound ( - std::unique_ptr<Rust::HIR::RangePatternBound> &bound, - Analysis::NodeMapping mappings, location_t locus) + Rust::HIR::RangePatternBound &bound, Analysis::NodeMapping mappings, + location_t locus) { TyTy::BaseType *resolved_bound = nullptr; - switch (bound->get_bound_type ()) + switch (bound.get_bound_type ()) { case HIR::RangePatternBound::RangePatternBoundType::LITERAL: { - HIR::RangePatternBoundLiteral &ref - = *static_cast<HIR::RangePatternBoundLiteral *> (bound.get ()); + auto &ref = static_cast<HIR::RangePatternBoundLiteral &> (bound); HIR::Literal lit = ref.get_literal (); @@ -450,18 +618,16 @@ TypeCheckPattern::typecheck_range_pattern_bound ( break; case HIR::RangePatternBound::RangePatternBoundType::PATH: { - HIR::RangePatternBoundPath &ref - = *static_cast<HIR::RangePatternBoundPath *> (bound.get ()); + auto &ref = static_cast<HIR::RangePatternBoundPath &> (bound); - resolved_bound = TypeCheckExpr::Resolve (&ref.get_path ()); + resolved_bound = TypeCheckExpr::Resolve (ref.get_path ()); } break; case HIR::RangePatternBound::RangePatternBoundType::QUALPATH: { - HIR::RangePatternBoundQualPath &ref - = *static_cast<HIR::RangePatternBoundQualPath *> (bound.get ()); + auto &ref = static_cast<HIR::RangePatternBoundQualPath &> (bound); - resolved_bound = TypeCheckExpr::Resolve (&ref.get_qualified_path ()); + resolved_bound = TypeCheckExpr::Resolve (ref.get_qualified_path ()); } break; } @@ -478,7 +644,7 @@ TypeCheckPattern::visit (HIR::AltPattern &pattern) std::vector<TyTy::BaseType *> types; for (auto &alt_pattern : alts) { - types.push_back (TypeCheckPattern::Resolve (alt_pattern.get (), parent)); + types.push_back (TypeCheckPattern::Resolve (*alt_pattern, parent)); } TyTy::BaseType *alt_pattern_type @@ -497,16 +663,17 @@ TypeCheckPattern::visit (HIR::AltPattern &pattern) } TyTy::BaseType * -ClosureParamInfer::Resolve (HIR::Pattern *pattern) +ClosureParamInfer::Resolve (HIR::Pattern &pattern) { ClosureParamInfer resolver; - pattern->accept_vis (resolver); + pattern.accept_vis (resolver); if (resolver.infered->get_kind () != TyTy::TypeKind::ERROR) { - resolver.context->insert_implicit_type (resolver.infered); + resolver.context->insert_implicit_type (resolver.infered->get_ref (), + resolver.infered); resolver.mappings.insert_location (resolver.infered->get_ref (), - pattern->get_locus ()); + pattern.get_locus ()); } return resolver.infered; } @@ -537,7 +704,7 @@ void ClosureParamInfer::visit (HIR::ReferencePattern &pattern) { TyTy::BaseType *element - = ClosureParamInfer::Resolve (pattern.get_referenced_pattern ().get ()); + = ClosureParamInfer::Resolve (pattern.get_referenced_pattern ()); HirId id = pattern.get_mappings ().get_hirid (); infered = new TyTy::ReferenceType (id, TyTy::TyVar (element->get_ref ()), diff --git a/gcc/rust/typecheck/rust-hir-type-check-pattern.h b/gcc/rust/typecheck/rust-hir-type-check-pattern.h index ba45b65..d477181 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-pattern.h +++ b/gcc/rust/typecheck/rust-hir-type-check-pattern.h @@ -28,7 +28,7 @@ namespace Resolver { class TypeCheckPattern : public TypeCheckBase, public HIR::HIRPatternVisitor { public: - static TyTy::BaseType *Resolve (HIR::Pattern *pattern, + static TyTy::BaseType *Resolve (HIR::Pattern &pattern, TyTy::BaseType *parent); void visit (HIR::PathInExpression &pattern) override; @@ -47,9 +47,10 @@ public: private: TypeCheckPattern (TyTy::BaseType *parent); - TyTy::BaseType *typecheck_range_pattern_bound ( - std::unique_ptr<Rust::HIR::RangePatternBound> &bound, - Analysis::NodeMapping mappings, location_t locus); + TyTy::BaseType * + typecheck_range_pattern_bound (Rust::HIR::RangePatternBound &bound, + Analysis::NodeMapping mappings, + location_t locus); void emit_pattern_size_error (const HIR::Pattern &pattern, size_t expected_field_count, @@ -62,7 +63,7 @@ private: class ClosureParamInfer : private TypeCheckBase, private HIR::HIRPatternVisitor { public: - static TyTy::BaseType *Resolve (HIR::Pattern *pattern); + static TyTy::BaseType *Resolve (HIR::Pattern &pattern); void visit (HIR::PathInExpression &pattern) override; void visit (HIR::StructPattern &pattern) override; diff --git a/gcc/rust/typecheck/rust-hir-type-check-stmt.cc b/gcc/rust/typecheck/rust-hir-type-check-stmt.cc index 6d27d3d..4e53856 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-stmt.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-stmt.cc @@ -28,23 +28,23 @@ namespace Rust { namespace Resolver { TyTy::BaseType * -TypeCheckStmt::Resolve (HIR::Stmt *stmt) +TypeCheckStmt::Resolve (HIR::Stmt &stmt) { TypeCheckStmt resolver; - stmt->accept_vis (resolver); + stmt.accept_vis (resolver); return resolver.infered; } void TypeCheckStmt::visit (HIR::ExprStmt &stmt) { - infered = TypeCheckExpr::Resolve (stmt.get_expr ().get ()); + infered = TypeCheckExpr::Resolve (stmt.get_expr ()); } void TypeCheckStmt::visit (HIR::EmptyStmt &stmt) { - infered = TyTy::TupleType::get_unit_type (stmt.get_mappings ().get_hirid ()); + infered = TyTy::TupleType::get_unit_type (); } void @@ -52,21 +52,20 @@ TypeCheckStmt::visit (HIR::ExternBlock &extern_block) { for (auto &item : extern_block.get_extern_items ()) { - TypeCheckTopLevelExternItem::Resolve (item.get (), extern_block); + TypeCheckTopLevelExternItem::Resolve (*item, extern_block); } } void TypeCheckStmt::visit (HIR::ConstantItem &constant) { - TyTy::BaseType *type = TypeCheckType::Resolve (constant.get_type ().get ()); - TyTy::BaseType *expr_type - = TypeCheckExpr::Resolve (constant.get_expr ().get ()); + TyTy::BaseType *type = TypeCheckType::Resolve (constant.get_type ()); + TyTy::BaseType *expr_type = TypeCheckExpr::Resolve (constant.get_expr ()); infered = coercion_site ( constant.get_mappings ().get_hirid (), - TyTy::TyWithLocation (type, constant.get_type ()->get_locus ()), - TyTy::TyWithLocation (expr_type, constant.get_expr ()->get_locus ()), + TyTy::TyWithLocation (type, constant.get_type ().get_locus ()), + TyTy::TyWithLocation (expr_type, constant.get_expr ().get_locus ()), constant.get_locus ()); context->insert_type (constant.get_mappings (), infered); } @@ -74,15 +73,15 @@ TypeCheckStmt::visit (HIR::ConstantItem &constant) void TypeCheckStmt::visit (HIR::LetStmt &stmt) { - infered = TyTy::TupleType::get_unit_type (stmt.get_mappings ().get_hirid ()); + infered = TyTy::TupleType::get_unit_type (); - HIR::Pattern &stmt_pattern = *stmt.get_pattern (); + auto &stmt_pattern = stmt.get_pattern (); TyTy::BaseType *init_expr_ty = nullptr; location_t init_expr_locus = UNKNOWN_LOCATION; if (stmt.has_init_expr ()) { - init_expr_locus = stmt.get_init_expr ()->get_locus (); - init_expr_ty = TypeCheckExpr::Resolve (stmt.get_init_expr ().get ()); + init_expr_locus = stmt.get_init_expr ().get_locus (); + init_expr_ty = TypeCheckExpr::Resolve (stmt.get_init_expr ()); if (init_expr_ty->get_kind () == TyTy::TypeKind::ERROR) return; @@ -94,8 +93,8 @@ TypeCheckStmt::visit (HIR::LetStmt &stmt) location_t specified_ty_locus; if (stmt.has_type ()) { - specified_ty = TypeCheckType::Resolve (stmt.get_type ().get ()); - specified_ty_locus = stmt.get_type ()->get_locus (); + specified_ty = TypeCheckType::Resolve (stmt.get_type ()); + specified_ty_locus = stmt.get_type ().get_locus (); } // let x:i32 = 123; @@ -105,19 +104,19 @@ TypeCheckStmt::visit (HIR::LetStmt &stmt) TyTy::TyWithLocation (specified_ty, specified_ty_locus), TyTy::TyWithLocation (init_expr_ty, init_expr_locus), stmt.get_locus ()); - TypeCheckPattern::Resolve (&stmt_pattern, specified_ty); + TypeCheckPattern::Resolve (stmt_pattern, specified_ty); } else { // let x:i32; if (specified_ty != nullptr) { - TypeCheckPattern::Resolve (&stmt_pattern, specified_ty); + TypeCheckPattern::Resolve (stmt_pattern, specified_ty); } // let x = 123; else if (init_expr_ty != nullptr) { - TypeCheckPattern::Resolve (&stmt_pattern, init_expr_ty); + TypeCheckPattern::Resolve (stmt_pattern, init_expr_ty); } // let x; else @@ -127,7 +126,7 @@ TypeCheckStmt::visit (HIR::LetStmt &stmt) TyTy::InferType::InferTypeKind::GENERAL, TyTy::InferType::TypeHint::Default (), stmt.get_locus ()); - TypeCheckPattern::Resolve (&stmt_pattern, infer); + TypeCheckPattern::Resolve (stmt_pattern, infer); } } } @@ -135,12 +134,12 @@ TypeCheckStmt::visit (HIR::LetStmt &stmt) void TypeCheckStmt::visit (HIR::TypePath &path) { - infered = TypeCheckType::Resolve (&path); + infered = TypeCheckType::Resolve (path); } void TypeCheckStmt::visit (HIR::QualifiedPathInType &path) { - infered = TypeCheckType::Resolve (&path); + infered = TypeCheckType::Resolve (path); } void diff --git a/gcc/rust/typecheck/rust-hir-type-check-stmt.h b/gcc/rust/typecheck/rust-hir-type-check-stmt.h index 6d91372..d679805 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-stmt.h +++ b/gcc/rust/typecheck/rust-hir-type-check-stmt.h @@ -28,7 +28,7 @@ namespace Resolver { class TypeCheckStmt : private TypeCheckBase, private HIR::HIRStmtVisitor { public: - static TyTy::BaseType *Resolve (HIR::Stmt *stmt); + static TyTy::BaseType *Resolve (HIR::Stmt &stmt); void visit (HIR::ExprStmt &stmt) override; void visit (HIR::EmptyStmt &stmt) override; diff --git a/gcc/rust/typecheck/rust-hir-type-check-struct-field.h b/gcc/rust/typecheck/rust-hir-type-check-struct-field.h index cfa17ac..7e3a57a 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-struct-field.h +++ b/gcc/rust/typecheck/rust-hir-type-check-struct-field.h @@ -33,7 +33,7 @@ namespace Resolver { class TypeCheckStructExpr : public TypeCheckBase { public: - static TyTy::BaseType *Resolve (HIR::StructExprStructFields *expr); + static TyTy::BaseType *Resolve (HIR::StructExprStructFields &expr); // Helper for making any errors static Error @@ -49,7 +49,7 @@ protected: bool visit (HIR::StructExprFieldIdentifier &field); private: - TypeCheckStructExpr (HIR::Expr *e); + TypeCheckStructExpr (HIR::Expr &e); // result TyTy::BaseType *resolved; @@ -60,6 +60,9 @@ private: TyTy::BaseType *resolved_field_value_expr; std::set<std::string> fields_assigned; std::map<size_t, HIR::StructExprField *> adtFieldIndexToField; + + // parent + HIR::Expr &parent; }; } // namespace Resolver diff --git a/gcc/rust/typecheck/rust-hir-type-check-struct.cc b/gcc/rust/typecheck/rust-hir-type-check-struct.cc index 5018829..df1636a 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-struct.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-struct.cc @@ -24,18 +24,18 @@ namespace Rust { namespace Resolver { -TypeCheckStructExpr::TypeCheckStructExpr (HIR::Expr *e) +TypeCheckStructExpr::TypeCheckStructExpr (HIR::Expr &e) : TypeCheckBase (), - resolved (new TyTy::ErrorType (e->get_mappings ().get_hirid ())), + resolved (new TyTy::ErrorType (e.get_mappings ().get_hirid ())), struct_path_resolved (nullptr), - variant (&TyTy::VariantDef::get_error_node ()) + variant (&TyTy::VariantDef::get_error_node ()), parent (e) {} TyTy::BaseType * -TypeCheckStructExpr::Resolve (HIR::StructExprStructFields *expr) +TypeCheckStructExpr::Resolve (HIR::StructExprStructFields &expr) { TypeCheckStructExpr resolver (expr); - resolver.resolve (*expr); + resolver.resolve (expr); return resolver.resolved; } @@ -43,7 +43,7 @@ void TypeCheckStructExpr::resolve (HIR::StructExprStructFields &struct_expr) { TyTy::BaseType *struct_path_ty - = TypeCheckExpr::Resolve (&struct_expr.get_struct_name ()); + = TypeCheckExpr::Resolve (struct_expr.get_struct_name ()); if (struct_path_ty->get_kind () != TyTy::TypeKind::ADT) { rust_error_at (struct_expr.get_struct_name ().get_locus (), @@ -56,17 +56,18 @@ TypeCheckStructExpr::resolve (HIR::StructExprStructFields &struct_expr) if (struct_expr.has_struct_base ()) { TyTy::BaseType *base_resolved - = TypeCheckExpr::Resolve (struct_expr.struct_base->base_struct.get ()); + = TypeCheckExpr::Resolve (struct_expr.get_struct_base ().get_base ()); TyTy::BaseType *base_unify = unify_site ( - struct_expr.struct_base->base_struct->get_mappings ().get_hirid (), + struct_expr.get_struct_base ().get_base ().get_mappings ().get_hirid (), TyTy::TyWithLocation (struct_path_resolved), TyTy::TyWithLocation (base_resolved), - struct_expr.struct_base->base_struct->get_locus ()); + struct_expr.get_struct_base ().get_base ().get_locus ()); if (base_unify->get_kind () != struct_path_ty->get_kind ()) { - rust_fatal_error (struct_expr.struct_base->base_struct->get_locus (), - "incompatible types for base struct reference"); + rust_error_at ( + struct_expr.get_struct_base ().get_base ().get_locus (), + "incompatible types for base struct reference"); return; } @@ -81,7 +82,16 @@ TypeCheckStructExpr::resolve (HIR::StructExprStructFields &struct_expr) bool ok = context->lookup_variant_definition ( struct_expr.get_struct_name ().get_mappings ().get_hirid (), &variant_id); - rust_assert (ok); + if (!ok) + { + rich_location r (line_table, struct_expr.get_locus ()); + r.add_range (struct_expr.get_struct_name ().get_locus ()); + rust_error_at ( + struct_expr.get_struct_name ().get_locus (), ErrorCode::E0574, + "expected a struct, variant or union type, found enum %qs", + struct_path_resolved->get_name ().c_str ()); + return; + } ok = struct_path_resolved->lookup_variant_by_id (variant_id, &variant); rust_assert (ok); @@ -117,29 +127,14 @@ TypeCheckStructExpr::resolve (HIR::StructExprStructFields &struct_expr) break; } - if (!ok) - { - return; - } - - if (resolved_field_value_expr == nullptr) - { - rust_fatal_error (field->get_locus (), - "failed to resolve type for field"); - ok = false; - break; - } - - context->insert_type (field->get_mappings (), resolved_field_value_expr); + if (ok) + context->insert_type (field->get_mappings (), + resolved_field_value_expr); } - // something failed setting up the fields + // something failed setting up the fields and error's emitted if (!ok) - { - rust_error_at (struct_expr.get_locus (), - "constructor type resolution failure"); - return; - } + return; // check the arguments are all assigned and fix up the ordering std::vector<std::string> missing_field_names; @@ -190,26 +185,29 @@ TypeCheckStructExpr::resolve (HIR::StructExprStructFields &struct_expr) for (auto &missing : missing_fields) { HIR::Expr *receiver - = struct_expr.struct_base->base_struct->clone_expr_impl (); + = struct_expr.get_struct_base ().get_base ().clone_expr_impl (); HIR::StructExprField *implicit_field = nullptr; AST::AttrVec outer_attribs; auto crate_num = mappings.get_current_crate (); - Analysis::NodeMapping mapping ( - crate_num, - struct_expr.struct_base->base_struct->get_mappings () - .get_nodeid (), - mappings.get_next_hir_id (crate_num), UNKNOWN_LOCAL_DEFID); + Analysis::NodeMapping mapping (crate_num, + struct_expr.get_struct_base () + .get_base () + .get_mappings () + .get_nodeid (), + mappings.get_next_hir_id ( + crate_num), + UNKNOWN_LOCAL_DEFID); HIR::Expr *field_value = new HIR::FieldAccessExpr ( mapping, std::unique_ptr<HIR::Expr> (receiver), missing, std::move (outer_attribs), - struct_expr.struct_base->base_struct->get_locus ()); + struct_expr.get_struct_base ().get_base ().get_locus ()); implicit_field = new HIR::StructExprFieldIdentifierValue ( mapping, missing, std::unique_ptr<HIR::Expr> (field_value), - struct_expr.struct_base->base_struct->get_locus ()); + struct_expr.get_struct_base ().get_base ().get_locus ()); size_t field_index; bool ok = variant->lookup_field (missing, nullptr, &field_index); @@ -267,8 +265,11 @@ TypeCheckStructExpr::visit (HIR::StructExprFieldIdentifierValue &field) &field_index); if (!ok) { - rust_error_at (field.get_locus (), "unknown field"); - return true; + rich_location r (line_table, parent.get_locus ()); + r.add_range (field.get_locus ()); + rust_error_at (r, ErrorCode::E0560, "unknown field %qs", + field.field_name.as_string ().c_str ()); + return false; } auto it = adtFieldIndexToField.find (field_index); @@ -284,8 +285,8 @@ TypeCheckStructExpr::visit (HIR::StructExprFieldIdentifierValue &field) return false; } - TyTy::BaseType *value = TypeCheckExpr::Resolve (field.get_value ().get ()); - location_t value_locus = field.get_value ()->get_locus (); + TyTy::BaseType *value = TypeCheckExpr::Resolve (field.get_value ()); + location_t value_locus = field.get_value ().get_locus (); HirId coercion_site_id = field.get_mappings ().get_hirid (); resolved_field_value_expr @@ -313,8 +314,11 @@ TypeCheckStructExpr::visit (HIR::StructExprFieldIndexValue &field) bool ok = variant->lookup_field (field_name, &field_type, &field_index); if (!ok) { - rust_error_at (field.get_locus (), "unknown field"); - return true; + rich_location r (line_table, parent.get_locus ()); + r.add_range (field.get_locus ()); + rust_error_at (r, ErrorCode::E0560, "unknown field %qs", + field_name.c_str ()); + return false; } auto it = adtFieldIndexToField.find (field_index); @@ -330,8 +334,8 @@ TypeCheckStructExpr::visit (HIR::StructExprFieldIndexValue &field) return false; } - TyTy::BaseType *value = TypeCheckExpr::Resolve (field.get_value ().get ()); - location_t value_locus = field.get_value ()->get_locus (); + TyTy::BaseType *value = TypeCheckExpr::Resolve (field.get_value ()); + location_t value_locus = field.get_value ().get_locus (); HirId coercion_site_id = field.get_mappings ().get_hirid (); resolved_field_value_expr @@ -385,7 +389,7 @@ TypeCheckStructExpr::visit (HIR::StructExprFieldIdentifier &field) HIR::GenericArgs::create_empty ()); HIR::PathInExpression expr (mappings_copy2, {seg}, field.get_locus (), false, {}); - TyTy::BaseType *value = TypeCheckExpr::Resolve (&expr); + TyTy::BaseType *value = TypeCheckExpr::Resolve (expr); location_t value_locus = expr.get_locus (); HirId coercion_site_id = field.get_mappings ().get_hirid (); diff --git a/gcc/rust/typecheck/rust-hir-type-check-type.cc b/gcc/rust/typecheck/rust-hir-type-check-type.cc index f7ae8cc..6919093 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-type.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-type.cc @@ -18,6 +18,8 @@ #include "rust-hir-type-check-type.h" #include "options.h" +#include "optional.h" +#include "rust-hir-map.h" #include "rust-hir-trait-resolve.h" #include "rust-hir-type-check-expr.h" #include "rust-hir-path-probe.h" @@ -26,18 +28,19 @@ #include "rust-mapping-common.h" #include "rust-substitution-mapper.h" #include "rust-type-util.h" +#include "rust-system.h" namespace Rust { namespace Resolver { HIR::GenericArgs -TypeCheckResolveGenericArguments::resolve (HIR::TypePathSegment *segment) +TypeCheckResolveGenericArguments::resolve (HIR::TypePathSegment &segment) { - TypeCheckResolveGenericArguments resolver (segment->get_locus ()); - switch (segment->get_type ()) + TypeCheckResolveGenericArguments resolver (segment.get_locus ()); + switch (segment.get_type ()) { case HIR::TypePathSegment::SegmentType::GENERIC: - resolver.visit (static_cast<HIR::TypePathSegmentGeneric &> (*segment)); + resolver.visit (static_cast<HIR::TypePathSegmentGeneric &> (segment)); break; default: @@ -53,20 +56,20 @@ TypeCheckResolveGenericArguments::visit (HIR::TypePathSegmentGeneric &generic) } TyTy::BaseType * -TypeCheckType::Resolve (HIR::Type *type) +TypeCheckType::Resolve (HIR::Type &type) { // is it already resolved? auto context = TypeCheckContext::get (); TyTy::BaseType *resolved = nullptr; bool already_resolved - = context->lookup_type (type->get_mappings ().get_hirid (), &resolved); + = context->lookup_type (type.get_mappings ().get_hirid (), &resolved); if (already_resolved) return resolved; - TypeCheckType resolver (type->get_mappings ().get_hirid ()); - type->accept_vis (resolver); + TypeCheckType resolver (type.get_mappings ().get_hirid ()); + type.accept_vis (resolver); rust_assert (resolver.translated != nullptr); - resolver.context->insert_type (type->get_mappings (), resolver.translated); + resolver.context->insert_type (type.get_mappings (), resolver.translated); return resolver.translated; } @@ -82,20 +85,20 @@ TypeCheckType::visit (HIR::BareFunctionType &fntype) TyTy::BaseType *return_type; if (fntype.has_return_type ()) { - return_type = TypeCheckType::Resolve (fntype.get_return_type ().get ()); + return_type = TypeCheckType::Resolve (fntype.get_return_type ()); } else { // needs a new implicit ID HirId ref = mappings.get_next_hir_id (); - return_type = TyTy::TupleType::get_unit_type (ref); + return_type = TyTy::TupleType::get_unit_type (); context->insert_implicit_type (ref, return_type); } std::vector<TyTy::TyVar> params; for (auto ¶m : fntype.get_function_params ()) { - TyTy::BaseType *ptype = TypeCheckType::Resolve (param.get_type ().get ()); + TyTy::BaseType *ptype = TypeCheckType::Resolve (param.get_type ()); params.push_back (TyTy::TyVar (ptype->get_ref ())); } @@ -109,19 +112,14 @@ TypeCheckType::visit (HIR::TupleType &tuple) { if (tuple.is_unit_type ()) { - auto unit_node_id = resolver->get_unit_type_node_id (); - if (!context->lookup_builtin (unit_node_id, &translated)) - { - rust_error_at (tuple.get_locus (), - "failed to lookup builtin unit type"); - } + translated = TyTy::TupleType::get_unit_type (); return; } std::vector<TyTy::TyVar> fields; for (auto &elem : tuple.get_elems ()) { - auto field_ty = TypeCheckType::Resolve (elem.get ()); + auto field_ty = TypeCheckType::Resolve (*elem); fields.push_back (TyTy::TyVar (field_ty->get_ref ())); } @@ -136,11 +134,14 @@ TypeCheckType::visit (HIR::TypePath &path) // this can happen so we need to look up the root then resolve the // remaining segments if possible + bool wasBigSelf = false; size_t offset = 0; - NodeId resolved_node_id = UNKNOWN_NODEID; - TyTy::BaseType *root = resolve_root_path (path, &offset, &resolved_node_id); + TyTy::BaseType *root = resolve_root_path (path, &offset, &wasBigSelf); if (root->get_kind () == TyTy::TypeKind::ERROR) - return; + { + rust_debug_loc (path.get_locus (), "failed to resolve type-path type"); + return; + } TyTy::BaseType *path_type = root->clone (); path_type->set_ref (path.get_mappings ().get_hirid ()); @@ -150,21 +151,25 @@ TypeCheckType::visit (HIR::TypePath &path) if (fully_resolved) { translated = path_type; + rust_debug_loc (path.get_locus (), "root resolved type-path to: [%s]", + translated->debug_str ().c_str ()); return; } translated - = resolve_segments (resolved_node_id, path.get_mappings ().get_hirid (), - path.get_segments (), offset, path_type, - path.get_mappings (), path.get_locus ()); + = resolve_segments (path.get_mappings ().get_hirid (), path.get_segments (), + offset, path_type, path.get_mappings (), + path.get_locus (), wasBigSelf); + + rust_debug_loc (path.get_locus (), "resolved type-path to: [%s]", + translated->debug_str ().c_str ()); } void TypeCheckType::visit (HIR::QualifiedPathInType &path) { HIR::QualifiedPathType qual_path_type = path.get_path_type (); - TyTy::BaseType *root - = TypeCheckType::Resolve (qual_path_type.get_type ().get ()); + TyTy::BaseType *root = TypeCheckType::Resolve (qual_path_type.get_type ()); if (root->get_kind () == TyTy::TypeKind::ERROR) { rust_debug_loc (path.get_locus (), "failed to resolve the root"); @@ -173,39 +178,25 @@ TypeCheckType::visit (HIR::QualifiedPathInType &path) if (!qual_path_type.has_as_clause ()) { - // then this is just a normal path-in-expression - NodeId root_resolved_node_id = UNKNOWN_NODEID; - bool ok = resolver->lookup_resolved_type ( - qual_path_type.get_type ()->get_mappings ().get_nodeid (), - &root_resolved_node_id); - rust_assert (ok); - - translated = resolve_segments (root_resolved_node_id, - path.get_mappings ().get_hirid (), - path.get_segments (), 0, translated, - path.get_mappings (), path.get_locus ()); + translated + = resolve_segments (path.get_mappings ().get_hirid (), + path.get_segments (), 0, translated, + path.get_mappings (), path.get_locus (), false); return; } // Resolve the trait now - std::unique_ptr<HIR::TypePath> &trait_path_ref = qual_path_type.get_trait (); - TraitReference *trait_ref = TraitResolver::Resolve (*trait_path_ref.get ()); + auto &trait_path_ref = qual_path_type.get_trait (); + TraitReference *trait_ref = TraitResolver::Resolve (trait_path_ref); if (trait_ref->is_error ()) return; - // does this type actually implement this type-bound? - if (!TypeBoundsProbe::is_bound_satisfied_for_type (root, trait_ref)) - { - rust_error_at (qual_path_type.get_locus (), - "root does not satisfy specified trait-bound"); - return; - } - // get the predicate for the bound auto specified_bound - = get_predicate_from_bound (*qual_path_type.get_trait ().get (), - qual_path_type.get_type ().get ()); + = get_predicate_from_bound (qual_path_type.get_trait (), + qual_path_type.get_type (), + BoundPolarity::RegularBound, true); if (specified_bound.is_error ()) return; @@ -213,18 +204,17 @@ TypeCheckType::visit (HIR::QualifiedPathInType &path) root->inherit_bounds ({specified_bound}); // lookup the associated item from the specified bound - std::unique_ptr<HIR::TypePathSegment> &item_seg - = path.get_associated_segment (); - HIR::PathIdentSegment item_seg_identifier = item_seg->get_ident_segment (); + HIR::TypePathSegment &item_seg = path.get_associated_segment (); + HIR::PathIdentSegment item_seg_identifier = item_seg.get_ident_segment (); TyTy::TypeBoundPredicateItem item = specified_bound.lookup_associated_item (item_seg_identifier.as_string ()); if (item.is_error ()) { std::string item_seg_ident_name, rich_msg; - item_seg_ident_name = qual_path_type.get_trait ()->as_string (); + item_seg_ident_name = qual_path_type.get_trait ().as_string (); rich_msg = "not found in `" + item_seg_ident_name + "`"; - rich_location richloc (line_table, item_seg->get_locus ()); + rich_location richloc (line_table, item_seg.get_locus ()); richloc.add_fixit_replace (rich_msg.c_str ()); rust_error_at (richloc, ErrorCode::E0576, @@ -264,7 +254,6 @@ TypeCheckType::visit (HIR::QualifiedPathInType &path) } } - NodeId root_resolved_node_id = UNKNOWN_NODEID; if (impl_item == nullptr) { // this may be valid as there could be a default trait implementation here @@ -272,41 +261,32 @@ TypeCheckType::visit (HIR::QualifiedPathInType &path) // not because this will have already been validated as part of the trait // impl block translated = item.get_tyty_for_receiver (root); - root_resolved_node_id - = item.get_raw_item ()->get_mappings ().get_nodeid (); } else { HirId impl_item_id = impl_item->get_impl_mappings ().get_hirid (); bool ok = query_type (impl_item_id, &translated); if (!ok) - { - // FIXME - // I think query_type should error if required here anyway - return; - } + return; if (!args.is_error ()) { // apply the args translated = SubstMapperInternal::Resolve (translated, args); } - - root_resolved_node_id = impl_item->get_impl_mappings ().get_nodeid (); } // turbo-fish segment path::<ty> - if (item_seg->get_type () == HIR::TypePathSegment::SegmentType::GENERIC) + if (item_seg.get_type () == HIR::TypePathSegment::SegmentType::GENERIC) { - HIR::TypePathSegmentGeneric &generic_seg - = static_cast<HIR::TypePathSegmentGeneric &> (*item_seg.get ()); + auto &generic_seg = static_cast<HIR::TypePathSegmentGeneric &> (item_seg); // turbo-fish segment path::<ty> if (generic_seg.has_generic_args ()) { if (!translated->has_substitutions_defined ()) { - rust_error_at (item_seg->get_locus (), + rust_error_at (item_seg.get_locus (), "substitutions not supported for %s", translated->as_string ().c_str ()); translated @@ -324,25 +304,21 @@ TypeCheckType::visit (HIR::QualifiedPathInType &path) // continue on as a path-in-expression bool fully_resolved = path.get_segments ().empty (); if (fully_resolved) - { - resolver->insert_resolved_type (path.get_mappings ().get_nodeid (), - root_resolved_node_id); - context->insert_receiver (path.get_mappings ().get_hirid (), root); - return; - } + return; translated - = resolve_segments (root_resolved_node_id, - path.get_mappings ().get_hirid (), path.get_segments (), - 0, translated, path.get_mappings (), path.get_locus ()); + = resolve_segments (path.get_mappings ().get_hirid (), path.get_segments (), + 0, translated, path.get_mappings (), path.get_locus (), + false); } TyTy::BaseType * TypeCheckType::resolve_root_path (HIR::TypePath &path, size_t *offset, - NodeId *root_resolved_node_id) + bool *wasBigSelf) { TyTy::BaseType *root_tyty = nullptr; *offset = 0; + for (size_t i = 0; i < path.get_num_segments (); i++) { std::unique_ptr<HIR::TypePathSegment> &seg = path.get_segments ().at (i); @@ -354,19 +330,25 @@ TypeCheckType::resolve_root_path (HIR::TypePath &path, size_t *offset, // then lookup the reference_node_id NodeId ref_node_id = UNKNOWN_NODEID; - // FIXME: HACK: ARTHUR: Remove this - if (flag_name_resolution_2_0) + if (seg->is_lang_item ()) + ref_node_id = Analysis::Mappings::get ().get_lang_item_node ( + seg->get_lang_item ()); + else { - auto nr_ctx - = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - // assign the ref_node_id if we've found something - nr_ctx.lookup (path.get_mappings ().get_nodeid ()) - .map ([&ref_node_id, &path] (NodeId resolved) { - ref_node_id = resolved; - }); + // FIXME: HACK: ARTHUR: Remove this + if (flag_name_resolution_2_0) + { + auto &nr_ctx = Resolver2_0::ImmutableNameResolutionContext::get () + .resolver (); + + // assign the ref_node_id if we've found something + nr_ctx.lookup (ast_node_id) + .map ( + [&ref_node_id] (NodeId resolved) { ref_node_id = resolved; }); + } + else if (!resolver->lookup_resolved_name (ast_node_id, &ref_node_id)) + resolver->lookup_resolved_type (ast_node_id, &ref_node_id); } - else if (!resolver->lookup_resolved_name (ast_node_id, &ref_node_id)) - resolver->lookup_resolved_type (ast_node_id, &ref_node_id); // ref_node_id is the NodeId that the segments refers to. if (ref_node_id == UNKNOWN_NODEID) @@ -375,12 +357,22 @@ TypeCheckType::resolve_root_path (HIR::TypePath &path, size_t *offset, { rust_error_at (seg->get_locus (), "unknown reference for resolved name: %qs", - seg->get_ident_segment ().as_string ().c_str ()); + seg->as_string ().c_str ()); + return new TyTy::ErrorType (path.get_mappings ().get_hirid ()); + } + else if (root_tyty == nullptr) + { + rust_error_at (seg->get_locus (), + "unknown reference for resolved name: %qs", + seg->as_string ().c_str ()); return new TyTy::ErrorType (path.get_mappings ().get_hirid ()); } return root_tyty; } + if (seg->is_ident_only () && seg->as_string () == "Self") + *wasBigSelf = true; + // node back to HIR tl::optional<HirId> hid = mappings.lookup_node_to_hir (ref_node_id); if (!hid.has_value ()) @@ -425,12 +417,14 @@ TypeCheckType::resolve_root_path (HIR::TypePath &path, size_t *offset, TyTy::BaseType *lookup = nullptr; if (!query_type (ref, &lookup)) { - if (is_root) + if (is_root || root_tyty == nullptr) { rust_error_at (seg->get_locus (), - "failed to resolve root segment"); + "failed to resolve type path segment: %qs", + seg->as_string ().c_str ()); return new TyTy::ErrorType (path.get_mappings ().get_hirid ()); } + return root_tyty; } @@ -457,13 +451,13 @@ TypeCheckType::resolve_root_path (HIR::TypePath &path, size_t *offset, // turbo-fish segment path::<ty> if (seg->is_generic_segment ()) { - HIR::TypePathSegmentGeneric *generic_segment - = static_cast<HIR::TypePathSegmentGeneric *> (seg.get ()); + auto &generic_segment + = static_cast<HIR::TypePathSegmentGeneric &> (*seg); auto regions = context->regions_from_generic_args ( - generic_segment->get_generic_args ()); + generic_segment.get_generic_args ()); lookup = SubstMapper::Resolve (lookup, path.get_locus (), - &generic_segment->get_generic_args (), + &generic_segment.get_generic_args (), regions); if (lookup->get_kind () == TyTy::TypeKind::ERROR) return new TyTy::ErrorType (seg->get_mappings ().get_hirid ()); @@ -477,7 +471,6 @@ TypeCheckType::resolve_root_path (HIR::TypePath &path, size_t *offset, context->regions_from_generic_args (empty)); } - *root_resolved_node_id = ref_node_id; *offset = *offset + 1; root_tyty = lookup; @@ -490,14 +483,58 @@ TypeCheckType::resolve_root_path (HIR::TypePath &path, size_t *offset, return root_tyty; } +bool +TypeCheckType::resolve_associated_type (const std::string &search, + TypeCheckBlockContextItem &ctx, + TyTy::BaseType **result) +{ + if (ctx.is_trait_block ()) + { + HIR::Trait &trait = ctx.get_trait (); + for (auto &item : trait.get_trait_items ()) + { + if (item->get_item_kind () != HIR::TraitItem::TraitItemKind::TYPE) + continue; + + if (item->trait_identifier () == search) + { + HirId item_id = item->get_mappings ().get_hirid (); + if (query_type (item_id, result)) + return true; + } + } + + // FIXME + // query any parent trait? + + return false; + } + + // look for any segment in here which matches + HIR::ImplBlock &block = ctx.get_impl_block (); + for (auto &item : block.get_impl_items ()) + { + if (item->get_impl_item_type () != HIR::ImplItem::TYPE_ALIAS) + continue; + + if (item->get_impl_item_name () == search) + { + HirId item_id = item->get_impl_mappings ().get_hirid (); + if (query_type (item_id, result)) + return true; + } + } + + return false; +} + TyTy::BaseType * TypeCheckType::resolve_segments ( - NodeId root_resolved_node_id, HirId expr_id, - std::vector<std::unique_ptr<HIR::TypePathSegment>> &segments, size_t offset, - TyTy::BaseType *tyseg, const Analysis::NodeMapping &expr_mappings, - location_t expr_locus) + HirId expr_id, std::vector<std::unique_ptr<HIR::TypePathSegment>> &segments, + size_t offset, TyTy::BaseType *tyseg, + const Analysis::NodeMapping &expr_mappings, location_t expr_locus, + bool tySegIsBigSelf) { - NodeId resolved_node_id = root_resolved_node_id; TyTy::BaseType *prev_segment = tyseg; for (size_t i = offset; i < segments.size (); i++) { @@ -508,76 +545,84 @@ TypeCheckType::resolve_segments ( bool probe_bounds = true; bool probe_impls = !reciever_is_generic; bool ignore_mandatory_trait_items = !reciever_is_generic; + bool first_segment = i == offset; + bool selfResolveOk = false; - // probe the path is done in two parts one where we search impls if no - // candidate is found then we search extensions from traits - auto candidates - = PathProbeType::Probe (prev_segment, seg->get_ident_segment (), - probe_impls, false, - ignore_mandatory_trait_items); - if (candidates.size () == 0) + if (first_segment && tySegIsBigSelf + && context->block_context ().is_in_context () + && context->block_context ().peek ().is_impl_block ()) { - candidates + TypeCheckBlockContextItem ctx = context->block_context ().peek (); + TyTy::BaseType *lookup = nullptr; + selfResolveOk + = resolve_associated_type (seg->as_string (), ctx, &lookup); + if (selfResolveOk) + { + prev_segment = tyseg; + tyseg = lookup; + } + } + if (!selfResolveOk) + { + // probe the path is done in two parts one where we search impls if no + // candidate is found then we search extensions from traits + auto candidates = PathProbeType::Probe (prev_segment, seg->get_ident_segment (), - false, probe_bounds, + probe_impls, false, ignore_mandatory_trait_items); - if (candidates.size () == 0) { - rust_error_at ( - seg->get_locus (), - "failed to resolve path segment using an impl Probe"); + candidates + = PathProbeType::Probe (prev_segment, seg->get_ident_segment (), + false, probe_bounds, + ignore_mandatory_trait_items); + if (candidates.size () == 0) + { + prev_segment->debug (); + rust_error_at ( + seg->get_locus (), + "failed to resolve path segment using an impl Probe"); + return new TyTy::ErrorType (expr_id); + } + } + + if (candidates.size () > 1) + { + ReportMultipleCandidateError::Report (candidates, + seg->get_ident_segment (), + seg->get_locus ()); return new TyTy::ErrorType (expr_id); } - } - if (candidates.size () > 1) - { - ReportMultipleCandidateError::Report (candidates, - seg->get_ident_segment (), - seg->get_locus ()); - return new TyTy::ErrorType (expr_id); - } + auto &candidate = *candidates.begin (); + prev_segment = tyseg; + tyseg = candidate.ty; - auto &candidate = *candidates.begin (); - prev_segment = tyseg; - tyseg = candidate.ty; + if (candidate.is_enum_candidate ()) + { + TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (tyseg); + auto last_variant = adt->get_variants (); + TyTy::VariantDef *variant = last_variant.back (); - if (candidate.is_enum_candidate ()) - { - TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (tyseg); - auto last_variant = adt->get_variants (); - TyTy::VariantDef *variant = last_variant.back (); - - rich_location richloc (line_table, seg->get_locus ()); - richloc.add_fixit_replace ("not a type"); - - rust_error_at (richloc, ErrorCode::E0573, - "expected type, found variant of %<%s::%s%>", - adt->get_name ().c_str (), - variant->get_identifier ().c_str ()); - return new TyTy::ErrorType (expr_id); - } + rich_location richloc (line_table, seg->get_locus ()); + richloc.add_fixit_replace ("not a type"); - if (candidate.is_impl_candidate ()) - { - resolved_node_id - = candidate.item.impl.impl_item->get_impl_mappings ().get_nodeid (); - } - else - { - resolved_node_id - = candidate.item.trait.item_ref->get_mappings ().get_nodeid (); + rust_error_at (richloc, ErrorCode::E0573, + "expected type, found variant of %<%s::%s%>", + adt->get_name ().c_str (), + variant->get_identifier ().c_str ()); + return new TyTy::ErrorType (expr_id); + } } if (seg->is_generic_segment ()) { - auto *generic_segment - = static_cast<HIR::TypePathSegmentGeneric *> (seg.get ()); + auto &generic_segment + = static_cast<HIR::TypePathSegmentGeneric &> (*seg); std::vector<TyTy::Region> regions; for (auto &lifetime : - generic_segment->get_generic_args ().get_lifetime_args ()) + generic_segment.get_generic_args ().get_lifetime_args ()) { auto region = context->lookup_and_resolve_lifetime (lifetime); if (!region.has_value ()) @@ -590,46 +635,13 @@ TypeCheckType::resolve_segments ( } tyseg = SubstMapper::Resolve (tyseg, expr_locus, - &generic_segment->get_generic_args (), + &generic_segment.get_generic_args (), regions); if (tyseg->get_kind () == TyTy::TypeKind::ERROR) return new TyTy::ErrorType (expr_id); } } - context->insert_receiver (expr_mappings.get_hirid (), prev_segment); - rust_assert (resolved_node_id != UNKNOWN_NODEID); - - // lookup if the name resolver was able to canonically resolve this or not - NodeId path_resolved_id = UNKNOWN_NODEID; - if (resolver->lookup_resolved_name (expr_mappings.get_nodeid (), - &path_resolved_id)) - { - rust_assert (path_resolved_id == resolved_node_id); - } - // check the type scope - else if (resolver->lookup_resolved_type (expr_mappings.get_nodeid (), - &path_resolved_id)) - { - rust_assert (path_resolved_id == resolved_node_id); - } - else - { - // name scope first - if (resolver->get_name_scope ().decl_was_declared_here (resolved_node_id)) - { - resolver->insert_resolved_name (expr_mappings.get_nodeid (), - resolved_node_id); - } - // check the type scope - else if (resolver->get_type_scope ().decl_was_declared_here ( - resolved_node_id)) - { - resolver->insert_resolved_type (expr_mappings.get_nodeid (), - resolved_node_id); - } - } - return tyseg; } @@ -639,6 +651,11 @@ TypeCheckType::visit (HIR::TraitObjectType &type) std::vector<TyTy::TypeBoundPredicate> specified_bounds; for (auto &bound : type.get_type_param_bounds ()) { + // TODO: here we need to check if there are additional bounds that aren't + // auto traits. this is an error. for example, `dyn A + Sized + Sync` is + // okay, because Sized and Sync are both auto traits but `dyn A + Copy + + // Clone` is not okay and should error out. + if (bound->get_bound_type () != HIR::TypeParamBound::BoundType::TRAITBOUND) continue; @@ -654,7 +671,7 @@ TypeCheckType::visit (HIR::TraitObjectType &type) TyTy::TypeBoundPredicate predicate = get_predicate_from_bound ( trait_bound.get_path (), - nullptr /*this will setup a PLACEHOLDER for self*/); + tl::nullopt /*this will setup a PLACEHOLDER for self*/); if (!predicate.is_error () && predicate.is_object_safe (true, type.get_locus ())) @@ -668,35 +685,41 @@ TypeCheckType::visit (HIR::TraitObjectType &type) } void +TypeCheckType::visit (HIR::ParenthesisedType &type) +{ + // I think this really needs to be a tuple.. but will sort that out when we + // fix the parser issue + translated = TypeCheckType::Resolve (type.get_type_in_parens ()); +} + +void TypeCheckType::visit (HIR::ArrayType &type) { - auto capacity_type = TypeCheckExpr::Resolve (type.get_size_expr ().get ()); + auto capacity_type = TypeCheckExpr::Resolve (type.get_size_expr ()); if (capacity_type->get_kind () == TyTy::TypeKind::ERROR) return; TyTy::BaseType *expected_ty = nullptr; bool ok = context->lookup_builtin ("usize", &expected_ty); rust_assert (ok); - context->insert_type (type.get_size_expr ()->get_mappings (), expected_ty); + context->insert_type (type.get_size_expr ().get_mappings (), expected_ty); - unify_site (type.get_size_expr ()->get_mappings ().get_hirid (), + unify_site (type.get_size_expr ().get_mappings ().get_hirid (), TyTy::TyWithLocation (expected_ty), TyTy::TyWithLocation (capacity_type, - type.get_size_expr ()->get_locus ()), - type.get_size_expr ()->get_locus ()); + type.get_size_expr ().get_locus ()), + type.get_size_expr ().get_locus ()); - TyTy::BaseType *base - = TypeCheckType::Resolve (type.get_element_type ().get ()); + TyTy::BaseType *base = TypeCheckType::Resolve (type.get_element_type ()); translated = new TyTy::ArrayType (type.get_mappings ().get_hirid (), - type.get_locus (), *type.get_size_expr (), + type.get_locus (), type.get_size_expr (), TyTy::TyVar (base->get_ref ())); } void TypeCheckType::visit (HIR::SliceType &type) { - TyTy::BaseType *base - = TypeCheckType::Resolve (type.get_element_type ().get ()); + TyTy::BaseType *base = TypeCheckType::Resolve (type.get_element_type ()); translated = new TyTy::SliceType (type.get_mappings ().get_hirid (), type.get_locus (), TyTy::TyVar (base->get_ref ())); @@ -704,7 +727,7 @@ TypeCheckType::visit (HIR::SliceType &type) void TypeCheckType::visit (HIR::ReferenceType &type) { - TyTy::BaseType *base = TypeCheckType::Resolve (type.get_base_type ().get ()); + TyTy::BaseType *base = TypeCheckType::Resolve (type.get_base_type ()); rust_assert (type.has_lifetime ()); auto region = context->lookup_and_resolve_lifetime (type.get_lifetime ()); if (!region.has_value ()) @@ -716,12 +739,12 @@ TypeCheckType::visit (HIR::ReferenceType &type) translated = new TyTy::ReferenceType (type.get_mappings ().get_hirid (), TyTy::TyVar (base->get_ref ()), type.get_mut (), region.value ()); -} // namespace Resolver +} void TypeCheckType::visit (HIR::RawPointerType &type) { - TyTy::BaseType *base = TypeCheckType::Resolve (type.get_base_type ().get ()); + TyTy::BaseType *base = TypeCheckType::Resolve (type.get_base_type ()); translated = new TyTy::PointerType (type.get_mappings ().get_hirid (), TyTy::TyVar (base->get_ref ()), type.get_mut ()); @@ -746,28 +769,70 @@ TypeCheckType::visit (HIR::NeverType &type) translated = lookup->clone (); } +void +TypeCheckType::visit (HIR::ImplTraitType &type) +{ + std::vector<TyTy::TypeBoundPredicate> specified_bounds; + for (auto &bound : type.get_type_param_bounds ()) + { + if (bound->get_bound_type () + != HIR::TypeParamBound::BoundType::TRAITBOUND) + continue; + + HIR::TypeParamBound &b = *bound.get (); + HIR::TraitBound &trait_bound = static_cast<HIR::TraitBound &> (b); + + auto binder_pin = context->push_lifetime_binder (); + for (auto &lifetime_param : trait_bound.get_for_lifetimes ()) + { + context->intern_and_insert_lifetime (lifetime_param.get_lifetime ()); + } + + TyTy::TypeBoundPredicate predicate = get_predicate_from_bound ( + trait_bound.get_path (), + tl::nullopt /*this will setup a PLACEHOLDER for self*/); + + if (!predicate.is_error () + && predicate.is_object_safe (true, type.get_locus ())) + specified_bounds.push_back (std::move (predicate)); + } + + translated = new TyTy::OpaqueType (type.get_locus (), + type.get_mappings ().get_hirid (), + specified_bounds); +} + TyTy::ParamType * -TypeResolveGenericParam::Resolve (HIR::GenericParam *param, bool apply_sized) +TypeResolveGenericParam::Resolve (HIR::GenericParam ¶m, + bool resolve_trait_bounds, bool apply_sized) { - TypeResolveGenericParam resolver (apply_sized); - switch (param->get_kind ()) + TypeResolveGenericParam resolver (apply_sized, resolve_trait_bounds); + switch (param.get_kind ()) { case HIR::GenericParam::GenericKind::TYPE: - resolver.visit (static_cast<HIR::TypeParam &> (*param)); + resolver.visit (static_cast<HIR::TypeParam &> (param)); break; case HIR::GenericParam::GenericKind::CONST: - resolver.visit (static_cast<HIR::ConstGenericParam &> (*param)); + resolver.visit (static_cast<HIR::ConstGenericParam &> (param)); break; case HIR::GenericParam::GenericKind::LIFETIME: - resolver.visit (static_cast<HIR::LifetimeParam &> (*param)); + resolver.visit (static_cast<HIR::LifetimeParam &> (param)); break; } return resolver.resolved; } void +TypeResolveGenericParam::ApplyAnyTraitBounds (HIR::TypeParam ¶m, + TyTy::ParamType *pty) +{ + TypeResolveGenericParam resolver (true, true); + resolver.apply_trait_bounds (param, pty); +} + +void TypeResolveGenericParam::visit (HIR::LifetimeParam ¶m) { // nothing to do @@ -783,9 +848,22 @@ void TypeResolveGenericParam::visit (HIR::TypeParam ¶m) { if (param.has_type ()) - TypeCheckType::Resolve (param.get_type ().get ()); + TypeCheckType::Resolve (param.get_type ()); + + resolved + = new TyTy::ParamType (param.get_type_representation ().as_string (), + param.get_locus (), + param.get_mappings ().get_hirid (), param, {}); - HIR::Type *implicit_self_bound = nullptr; + if (resolve_trait_bounds) + apply_trait_bounds (param, resolved); +} + +void +TypeResolveGenericParam::apply_trait_bounds (HIR::TypeParam ¶m, + TyTy::ParamType *pty) +{ + std::unique_ptr<HIR::Type> implicit_self_bound = nullptr; if (param.has_type_param_bounds ()) { // We need two possible parameter types. One with no Bounds and one with @@ -803,8 +881,8 @@ TypeResolveGenericParam::visit (HIR::TypeParam ¶m) param.get_mappings ().get_nodeid (), implicit_id, param.get_mappings ().get_local_defid ()); - implicit_self_bound - = new HIR::TypePath (mappings, {}, BUILTINS_LOCATION, false); + implicit_self_bound = std::make_unique<HIR::TypePath> ( + HIR::TypePath (mappings, {}, BUILTINS_LOCATION, false)); } std::map<DefId, std::vector<TyTy::TypeBoundPredicate>> predicates; @@ -815,8 +893,6 @@ TypeResolveGenericParam::visit (HIR::TypeParam ¶m) // // We can only do this when we are not resolving the implicit Self for Sized // itself - rust_debug_loc (param.get_locus (), "apply_sized: %s", - apply_sized ? "true" : "false"); if (apply_sized) { TyTy::TypeBoundPredicate sized_predicate @@ -833,13 +909,13 @@ TypeResolveGenericParam::visit (HIR::TypeParam ¶m) switch (bound->get_bound_type ()) { case HIR::TypeParamBound::BoundType::TRAITBOUND: { - HIR::TraitBound *b - = static_cast<HIR::TraitBound *> (bound.get ()); + HIR::TraitBound &b = static_cast<HIR::TraitBound &> (*bound); - TyTy::TypeBoundPredicate predicate - = get_predicate_from_bound (b->get_path (), - implicit_self_bound, - b->get_polarity ()); + TyTy::TypeBoundPredicate predicate = get_predicate_from_bound ( + b.get_path (), + tl::optional<std::reference_wrapper<HIR::Type>> ( + std::ref (*implicit_self_bound)), + b.get_polarity ()); if (!predicate.is_error ()) { switch (predicate.get_polarity ()) @@ -852,7 +928,7 @@ TypeResolveGenericParam::visit (HIR::TypeParam ¶m) else { // emit error message - rich_location r (line_table, b->get_locus ()); + rich_location r (line_table, b.get_locus ()); r.add_range (predicate.get ()->get_locus ()); rust_error_at ( r, "antibound for %s is not applied here", @@ -891,10 +967,8 @@ TypeResolveGenericParam::visit (HIR::TypeParam ¶m) } } - resolved = new TyTy::ParamType (param.get_type_representation ().as_string (), - param.get_locus (), - param.get_mappings ().get_hirid (), param, - specified_bounds); + // inherit them + pty->inherit_bounds (specified_bounds); } void @@ -950,7 +1024,7 @@ ResolveWhereClauseItem::visit (HIR::TypeBoundWhereClauseItem &item) } auto &binding_type_path = item.get_bound_type (); - TyTy::BaseType *binding = TypeCheckType::Resolve (binding_type_path.get ()); + TyTy::BaseType *binding = TypeCheckType::Resolve (binding_type_path); // FIXME double check there might be a trait cycle here see TypeParam handling @@ -963,8 +1037,7 @@ ResolveWhereClauseItem::visit (HIR::TypeBoundWhereClauseItem &item) auto *b = static_cast<HIR::TraitBound *> (bound.get ()); TyTy::TypeBoundPredicate predicate - = get_predicate_from_bound (b->get_path (), - binding_type_path.get ()); + = get_predicate_from_bound (b->get_path (), binding_type_path); if (!predicate.is_error ()) specified_bounds.push_back (std::move (predicate)); } @@ -994,16 +1067,32 @@ ResolveWhereClauseItem::visit (HIR::TypeBoundWhereClauseItem &item) // When we apply these bounds we must lookup which type this binding // resolves to, as this is the type which will be used during resolution // of the block. - NodeId ast_node_id = binding_type_path->get_mappings ().get_nodeid (); + NodeId ast_node_id = binding_type_path.get_mappings ().get_nodeid (); // then lookup the reference_node_id NodeId ref_node_id = UNKNOWN_NODEID; - if (!resolver->lookup_resolved_type (ast_node_id, &ref_node_id)) + if (flag_name_resolution_2_0) + { + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); + + if (auto id = nr_ctx.lookup (ast_node_id)) + ref_node_id = *id; + } + else + { + NodeId id = UNKNOWN_NODEID; + + if (resolver->lookup_resolved_type (ast_node_id, &id)) + ref_node_id = id; + } + + if (ref_node_id == UNKNOWN_NODEID) { // FIXME rust_error_at (UNDEF_LOCATION, "Failed to lookup type reference for node: %s", - binding_type_path->as_string ().c_str ()); + binding_type_path.as_string ().c_str ()); return; } @@ -1016,7 +1105,7 @@ ResolveWhereClauseItem::visit (HIR::TypeBoundWhereClauseItem &item) { rust_error_at (mappings.lookup_location (*hid), "Failed to resolve where-clause binding type: %s", - binding_type_path->as_string ().c_str ()); + binding_type_path.as_string ().c_str ()); return; } diff --git a/gcc/rust/typecheck/rust-hir-type-check-type.h b/gcc/rust/typecheck/rust-hir-type-check-type.h index a440250..cc991b6 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-type.h +++ b/gcc/rust/typecheck/rust-hir-type-check-type.h @@ -31,7 +31,7 @@ namespace Resolver { class TypeCheckResolveGenericArguments : public TypeCheckBase { public: - static HIR::GenericArgs resolve (HIR::TypePathSegment *segment); + static HIR::GenericArgs resolve (HIR::TypePathSegment &segment); void visit (HIR::TypePathSegmentGeneric &generic); @@ -46,7 +46,7 @@ private: class TypeCheckType : public TypeCheckBase, public HIR::HIRTypeVisitor { public: - static TyTy::BaseType *Resolve (HIR::Type *type); + static TyTy::BaseType *Resolve (HIR::Type &type); void visit (HIR::BareFunctionType &fntype) override; void visit (HIR::TupleType &tuple) override; @@ -59,22 +59,12 @@ public: void visit (HIR::InferredType &type) override; void visit (HIR::NeverType &type) override; void visit (HIR::TraitObjectType &type) override; + void visit (HIR::ParenthesisedType &type) override; + void visit (HIR::ImplTraitType &type) override; - void visit (HIR::TypePathSegmentFunction &segment) override - { /* TODO */ - } - void visit (HIR::TraitBound &bound) override - { /* TODO */ - } - void visit (HIR::ImplTraitType &type) override - { /* TODO */ - } - void visit (HIR::ParenthesisedType &type) override - { /* TODO */ - } - void visit (HIR::ImplTraitTypeOneBound &type) override - { /* TODO */ - } + // These dont need to be implemented as they are segments or part of types + void visit (HIR::TypePathSegmentFunction &segment) override {} + void visit (HIR::TraitBound &bound) override {} private: TypeCheckType (HirId id) @@ -82,13 +72,17 @@ private: {} TyTy::BaseType *resolve_root_path (HIR::TypePath &path, size_t *offset, - NodeId *root_resolved_node_id); + bool *wasBigSelf); TyTy::BaseType *resolve_segments ( - NodeId root_resolved_node_id, HirId expr_id, - std::vector<std::unique_ptr<HIR::TypePathSegment>> &segments, size_t offset, - TyTy::BaseType *tyseg, const Analysis::NodeMapping &expr_mappings, - location_t expr_locus); + HirId expr_id, std::vector<std::unique_ptr<HIR::TypePathSegment>> &segments, + size_t offset, TyTy::BaseType *tyseg, + const Analysis::NodeMapping &expr_mappings, location_t expr_locus, + bool tySegIsBigSelf); + + bool resolve_associated_type (const std::string &search, + TypeCheckBlockContextItem &ctx, + TyTy::BaseType **result); TyTy::BaseType *translated; }; @@ -96,21 +90,28 @@ private: class TypeResolveGenericParam : public TypeCheckBase { public: - static TyTy::ParamType *Resolve (HIR::GenericParam *param, + static TyTy::ParamType *Resolve (HIR::GenericParam ¶m, + bool resolve_trait_bounds = true, bool apply_sized = true); + static void ApplyAnyTraitBounds (HIR::TypeParam ¶m, TyTy::ParamType *pty); + protected: void visit (HIR::TypeParam ¶m); void visit (HIR::LifetimeParam ¶m); void visit (HIR::ConstGenericParam ¶m); + void apply_trait_bounds (HIR::TypeParam ¶m, TyTy::ParamType *pty); + private: - TypeResolveGenericParam (bool apply_sized) - : TypeCheckBase (), resolved (nullptr), apply_sized (apply_sized) + TypeResolveGenericParam (bool apply_sized, bool resolve_trait_bounds) + : TypeCheckBase (), resolved (nullptr), apply_sized (apply_sized), + resolve_trait_bounds (resolve_trait_bounds) {} TyTy::ParamType *resolved; bool apply_sized; + bool resolve_trait_bounds; }; class ResolveWhereClauseItem : public TypeCheckBase diff --git a/gcc/rust/typecheck/rust-hir-type-check.cc b/gcc/rust/typecheck/rust-hir-type-check.cc index 45cb75d..fbaf323 100644 --- a/gcc/rust/typecheck/rust-hir-type-check.cc +++ b/gcc/rust/typecheck/rust-hir-type-check.cc @@ -19,10 +19,15 @@ #include "rust-hir-type-check.h" #include "rust-hir-full.h" #include "rust-hir-inherent-impl-overlap.h" +#include "rust-hir-pattern.h" #include "rust-hir-type-check-expr.h" #include "rust-hir-type-check-item.h" #include "rust-hir-type-check-pattern.h" #include "rust-hir-type-check-struct-field.h" +#include "rust-immutable-name-resolution-context.h" + +// for flag_name_resolution_2_0 +#include "options.h" extern bool saw_errors (void); @@ -136,11 +141,10 @@ TyTy::BaseType * TraitItemReference::get_type_from_constant ( /*const*/ HIR::TraitItemConst &constant) const { - TyTy::BaseType *type = TypeCheckType::Resolve (constant.get_type ().get ()); + TyTy::BaseType *type = TypeCheckType::Resolve (constant.get_type ()); if (constant.has_expr ()) { - TyTy::BaseType *expr - = TypeCheckExpr::Resolve (constant.get_expr ().get ()); + TyTy::BaseType *expr = TypeCheckExpr::Resolve (constant.get_expr ()); return unify_site (constant.get_mappings ().get_hirid (), TyTy::TyWithLocation (type), @@ -161,36 +165,9 @@ TraitItemReference::get_type_from_fn (/*const*/ HIR::TraitItemFunc &fn) const HIR::TraitFunctionDecl &function = fn.get_decl (); if (function.has_generics ()) { - for (auto &generic_param : function.get_generic_params ()) - { - switch (generic_param.get ()->get_kind ()) - { - case HIR::GenericParam::GenericKind::LIFETIME: { - auto lifetime_param - = static_cast<HIR::LifetimeParam &> (*generic_param); - - context->intern_and_insert_lifetime ( - lifetime_param.get_lifetime ()); - // TODO: Handle lifetime bounds - } - break; - case HIR::GenericParam::GenericKind::CONST: - // FIXME: Skipping Lifetime and Const completely until better - // handling. - break; - - case HIR::GenericParam::GenericKind::TYPE: { - auto param_type - = TypeResolveGenericParam::Resolve (generic_param.get ()); - context->insert_type (generic_param->get_mappings (), - param_type); - - substitutions.push_back (TyTy::SubstitutionParamMapping ( - static_cast<HIR::TypeParam &> (*generic_param), param_type)); - } - break; - } - } + TypeCheckBase::ResolveGenericParams (function.get_generic_params (), + substitutions, false /*is_foreign*/, + ABI::RUST); } if (function.has_where_clause ()) @@ -202,11 +179,10 @@ TraitItemReference::get_type_from_fn (/*const*/ HIR::TraitItemFunc &fn) const TyTy::BaseType *ret_type = nullptr; if (!function.has_return_type ()) - ret_type = TyTy::TupleType::get_unit_type (fn.get_mappings ().get_hirid ()); + ret_type = TyTy::TupleType::get_unit_type (); else { - auto resolved - = TypeCheckType::Resolve (function.get_return_type ().get ()); + auto resolved = TypeCheckType::Resolve (function.get_return_type ()); if (resolved->get_kind () == TyTy::TypeKind::ERROR) { rust_error_at (fn.get_locus (), "failed to resolve return type"); @@ -215,10 +191,11 @@ TraitItemReference::get_type_from_fn (/*const*/ HIR::TraitItemFunc &fn) const ret_type = resolved->clone (); ret_type->set_ref ( - function.get_return_type ()->get_mappings ().get_hirid ()); + function.get_return_type ().get_mappings ().get_hirid ()); } - std::vector<std::pair<HIR::Pattern *, TyTy::BaseType *> > params; + std::vector<TyTy::FnParam> params; + if (function.is_method ()) { // these are implicit mappings and not used @@ -231,17 +208,18 @@ TraitItemReference::get_type_from_fn (/*const*/ HIR::TraitItemFunc &fn) const // add the synthetic self param at the front, this is a placeholder // for compilation to know parameter names. The types are ignored // but we reuse the HIR identifier pattern which requires it - HIR::SelfParam &self_param = function.get_self (); - HIR::IdentifierPattern *self_pattern = new HIR::IdentifierPattern ( - mapping, {"self"}, self_param.get_locus (), self_param.is_ref (), - self_param.is_mut () ? Mutability::Mut : Mutability::Imm, - std::unique_ptr<HIR::Pattern> (nullptr)); + HIR::SelfParam &self_param = function.get_self_unchecked (); + std::unique_ptr<HIR::Pattern> self_pattern + = std::make_unique<HIR::IdentifierPattern> (HIR::IdentifierPattern ( + mapping, {"self"}, self_param.get_locus (), self_param.is_ref (), + self_param.is_mut () ? Mutability::Mut : Mutability::Imm, + std::unique_ptr<HIR::Pattern> (nullptr))); // might have a specified type TyTy::BaseType *self_type = nullptr; if (self_param.has_type ()) { - std::unique_ptr<HIR::Type> &specified_type = self_param.get_type (); - self_type = TypeCheckType::Resolve (specified_type.get ()); + HIR::Type &specified_type = self_param.get_type (); + self_type = TypeCheckType::Resolve (specified_type); } else { @@ -283,24 +261,38 @@ TraitItemReference::get_type_from_fn (/*const*/ HIR::TraitItemFunc &fn) const } context->insert_type (self_param.get_mappings (), self_type); - params.push_back ( - std::pair<HIR::Pattern *, TyTy::BaseType *> (self_pattern, self_type)); + params.push_back (TyTy::FnParam (std::move (self_pattern), self_type)); } for (auto ¶m : function.get_function_params ()) { // get the name as well required for later on - auto param_tyty = TypeCheckType::Resolve (param.get_type ().get ()); - params.push_back (std::pair<HIR::Pattern *, TyTy::BaseType *> ( - param.get_param_name ().get (), param_tyty)); - + auto param_tyty = TypeCheckType::Resolve (param.get_type ()); context->insert_type (param.get_mappings (), param_tyty); - TypeCheckPattern::Resolve (param.get_param_name ().get (), param_tyty); + TypeCheckPattern::Resolve (param.get_param_name (), param_tyty); + // FIXME: Should we take the name ? Use a shared pointer instead ? + params.push_back ( + TyTy::FnParam (param.get_param_name ().clone_pattern (), param_tyty)); } auto &mappings = Analysis::Mappings::get (); - auto canonical_path - = mappings.lookup_canonical_path (fn.get_mappings ().get_nodeid ()); + + tl::optional<CanonicalPath> canonical_path; + if (flag_name_resolution_2_0) + { + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); + + canonical_path + = nr_ctx.values.to_canonical_path (fn.get_mappings ().get_nodeid ()); + } + else + { + canonical_path + = mappings.lookup_canonical_path (fn.get_mappings ().get_nodeid ()); + } + + rust_assert (canonical_path); RustIdent ident{*canonical_path, fn.get_locus ()}; auto resolved = new TyTy::FnType ( diff --git a/gcc/rust/typecheck/rust-hir-type-check.h b/gcc/rust/typecheck/rust-hir-type-check.h index 3fcb32a..18a65fe 100644 --- a/gcc/rust/typecheck/rust-hir-type-check.h +++ b/gcc/rust/typecheck/rust-hir-type-check.h @@ -22,6 +22,7 @@ #include "rust-hir-map.h" #include "rust-tyty.h" #include "rust-hir-trait-reference.h" +#include "rust-stacked-contexts.h" #include "rust-autoderef.h" #include "rust-tyty-region.h" #include "rust-tyty-variance-analysis.h" @@ -42,7 +43,7 @@ public: }; TypeCheckContextItem (HIR::Function *item); - TypeCheckContextItem (HIR::ImplBlock *impl_block, HIR::Function *item); + TypeCheckContextItem (HIR::ImplBlock &impl_block, HIR::Function *item); TypeCheckContextItem (HIR::TraitItemFunc *trait_item); TypeCheckContextItem (const TypeCheckContextItem &other); @@ -82,6 +83,37 @@ private: Item item; }; +class TypeCheckBlockContextItem +{ +public: + enum ItemType + { + IMPL_BLOCK, + TRAIT + }; + + TypeCheckBlockContextItem (HIR::ImplBlock *block); + TypeCheckBlockContextItem (HIR::Trait *trait); + + bool is_impl_block () const; + bool is_trait_block () const; + + HIR::ImplBlock &get_impl_block (); + HIR::Trait &get_trait (); + +private: + union Item + { + HIR::ImplBlock *block; + HIR::Trait *trait; + + Item (HIR::ImplBlock *block); + Item (HIR::Trait *trait); + }; + ItemType type; + Item item; +}; + /** * Interned lifetime representation in TyTy * @@ -135,10 +167,10 @@ public: bool lookup_builtin (NodeId id, TyTy::BaseType **type); bool lookup_builtin (std::string name, TyTy::BaseType **type); void insert_builtin (HirId id, NodeId ref, TyTy::BaseType *type); + const std::vector<std::unique_ptr<TyTy::BaseType>> &get_builtins () const; void insert_type (const Analysis::NodeMapping &mappings, TyTy::BaseType *type); - void insert_implicit_type (TyTy::BaseType *type); bool lookup_type (HirId id, TyTy::BaseType **type) const; void clear_type (TyTy::BaseType *ty); @@ -153,6 +185,9 @@ public: void push_return_type (TypeCheckContextItem item, TyTy::BaseType *return_type); void pop_return_type (); + + StackedContexts<TypeCheckBlockContextItem> &block_context (); + void iterate (std::function<bool (HirId, TyTy::BaseType *)> cb); bool have_loop_context () const; @@ -166,9 +201,6 @@ public: void insert_trait_reference (DefId id, TraitReference &&ref); bool lookup_trait_reference (DefId id, TraitReference **ref); - void insert_receiver (HirId id, TyTy::BaseType *t); - bool lookup_receiver (HirId id, TyTy::BaseType **ref); - void insert_associated_trait_impl (HirId id, AssociatedImplTrait &&associated); bool lookup_associated_trait_impl (HirId id, @@ -244,8 +276,8 @@ private: std::vector<std::pair<TypeCheckContextItem, TyTy::BaseType *>> return_type_stack; std::vector<TyTy::BaseType *> loop_type_stack; + StackedContexts<TypeCheckBlockContextItem> block_stack; std::map<DefId, TraitReference> trait_context; - std::map<HirId, TyTy::BaseType *> receiver_context; std::map<HirId, AssociatedImplTrait> associated_impl_traits; // trait-id -> list of < self-tyty:impl-id> @@ -349,6 +381,8 @@ private: /** Only to be used by the guard. */ void pop_binder () { binder_size_stack.pop (); } + bool binder_empty () { return binder_size_stack.empty (); } + /** * Switch from resolving a function header to a function body. */ @@ -424,7 +458,8 @@ public: ~LifetimeResolverGuard () { rust_assert (!ctx.lifetime_resolver_stack.empty ()); - ctx.lifetime_resolver_stack.top ().pop_binder (); + if (!ctx.lifetime_resolver_stack.top ().binder_empty ()) + ctx.lifetime_resolver_stack.top ().pop_binder (); if (kind == RESOLVER) { ctx.lifetime_resolver_stack.pop (); diff --git a/gcc/rust/typecheck/rust-substitution-mapper.cc b/gcc/rust/typecheck/rust-substitution-mapper.cc index dbf49be..f0bd1f8 100644 --- a/gcc/rust/typecheck/rust-substitution-mapper.cc +++ b/gcc/rust/typecheck/rust-substitution-mapper.cc @@ -34,6 +34,15 @@ SubstMapper::Resolve (TyTy::BaseType *base, location_t locus, HIR::GenericArgs *generics, const std::vector<TyTy::Region> ®ions) { + if (!valid_type (base)) + { + rich_location r (line_table, locus); + r.add_fixit_remove (generics->get_locus ()); + rust_error_at (r, ErrorCode::E0109, + "generic arguments are not allowed for this type"); + return base; + } + SubstMapper mapper (base->get_ref (), generics, regions, locus); base->accept_vis (mapper); rust_assert (mapper.resolved != nullptr); @@ -47,6 +56,17 @@ SubstMapper::InferSubst (TyTy::BaseType *base, location_t locus) } bool +SubstMapper::valid_type (TyTy::BaseType *base) +{ + bool is_fn = base->is<TyTy::FnType> (); + bool is_adt = base->is<TyTy::ADTType> (); + bool is_placeholder = base->is<TyTy::PlaceholderType> (); + bool is_projection = base->is<TyTy::ProjectionType> (); + + return is_fn || is_adt || is_placeholder || is_projection; +} + +bool SubstMapper::have_generic_args () const { return generics != nullptr; @@ -103,7 +123,12 @@ SubstMapper::visit (TyTy::ADTType &type) void SubstMapper::visit (TyTy::PlaceholderType &type) { - rust_assert (type.can_resolve ()); + if (!type.can_resolve ()) + { + resolved = &type; + return; + } + resolved = SubstMapper::Resolve (type.resolve (), locus, generics, regions); } @@ -192,8 +217,10 @@ SubstMapperInternal::visit (TyTy::FnType &type) { TyTy::SubstitutionArgumentMappings adjusted = type.adjust_mappings_for_this (mappings); - if (adjusted.is_error ()) + if (adjusted.is_error () && !mappings.trait_item_mode ()) return; + if (adjusted.is_error () && mappings.trait_item_mode ()) + adjusted = mappings; TyTy::BaseType *concrete = type.handle_substitions (adjusted); if (concrete != nullptr) @@ -205,8 +232,10 @@ SubstMapperInternal::visit (TyTy::ADTType &type) { TyTy::SubstitutionArgumentMappings adjusted = type.adjust_mappings_for_this (mappings); - if (adjusted.is_error ()) + if (adjusted.is_error () && !mappings.trait_item_mode ()) return; + if (adjusted.is_error () && mappings.trait_item_mode ()) + adjusted = mappings; TyTy::BaseType *concrete = type.handle_substitions (adjusted); if (concrete != nullptr) @@ -342,6 +371,11 @@ SubstMapperInternal::visit (TyTy::DynamicObjectType &type) { resolved = type.clone (); } +void +SubstMapperInternal::visit (TyTy::OpaqueType &type) +{ + resolved = type.handle_substitions (mappings); +} // SubstMapperFromExisting diff --git a/gcc/rust/typecheck/rust-substitution-mapper.h b/gcc/rust/typecheck/rust-substitution-mapper.h index bcd93fd..32ab71c 100644 --- a/gcc/rust/typecheck/rust-substitution-mapper.h +++ b/gcc/rust/typecheck/rust-substitution-mapper.h @@ -37,6 +37,8 @@ public: bool have_generic_args () const; + static bool valid_type (TyTy::BaseType *base); + void visit (TyTy::FnType &type) override; void visit (TyTy::ADTType &type) override; void visit (TyTy::PlaceholderType &type) override; @@ -63,6 +65,7 @@ public: void visit (TyTy::NeverType &) override { rust_unreachable (); } void visit (TyTy::DynamicObjectType &) override { rust_unreachable (); } void visit (TyTy::ClosureType &) override { rust_unreachable (); } + void visit (TyTy::OpaqueType &) override { rust_unreachable (); } private: SubstMapper (HirId ref, HIR::GenericArgs *generics, @@ -107,6 +110,7 @@ public: void visit (TyTy::StrType &type) override; void visit (TyTy::NeverType &type) override; void visit (TyTy::DynamicObjectType &type) override; + void visit (TyTy::OpaqueType &type) override; private: SubstMapperInternal (HirId ref, TyTy::SubstitutionArgumentMappings &mappings); @@ -146,6 +150,7 @@ public: void visit (TyTy::PlaceholderType &) override { rust_unreachable (); } void visit (TyTy::ProjectionType &) override { rust_unreachable (); } void visit (TyTy::DynamicObjectType &) override { rust_unreachable (); } + void visit (TyTy::OpaqueType &type) override { rust_unreachable (); } private: SubstMapperFromExisting (TyTy::BaseType *concrete, TyTy::BaseType *receiver); @@ -185,6 +190,7 @@ public: void visit (const TyTy::PlaceholderType &) override {} void visit (const TyTy::ProjectionType &) override {} void visit (const TyTy::DynamicObjectType &) override {} + void visit (const TyTy::OpaqueType &type) override {} private: GetUsedSubstArgs (); diff --git a/gcc/rust/typecheck/rust-type-util.cc b/gcc/rust/typecheck/rust-type-util.cc index 0ed7124..c6c5b4b 100644 --- a/gcc/rust/typecheck/rust-type-util.cc +++ b/gcc/rust/typecheck/rust-type-util.cc @@ -22,10 +22,13 @@ #include "rust-hir-type-check-implitem.h" #include "rust-hir-type-check-item.h" #include "rust-hir-type-check.h" +#include "rust-hir-type-check-type.h" #include "rust-casts.h" #include "rust-unify.h" #include "rust-coercion.h" #include "rust-hir-type-bounds.h" +#include "rust-immutable-name-resolution-context.h" +#include "options.h" namespace Rust { namespace Resolver { @@ -34,6 +37,7 @@ bool query_type (HirId reference, TyTy::BaseType **result) { auto &mappings = Analysis::Mappings::get (); + auto &resolver = *Resolver::get (); TypeCheckContext *context = TypeCheckContext::get (); if (context->query_in_progress (reference)) @@ -87,8 +91,44 @@ query_type (HirId reference, TyTy::BaseType **result) // is it an impl_type? if (auto impl_block_by_type = mappings.lookup_impl_block_type (reference)) { - *result - = TypeCheckItem::ResolveImplBlockSelf (*impl_block_by_type.value ()); + // found an impl item + HIR::ImplBlock *impl = impl_block_by_type.value (); + rust_debug_loc (impl->get_locus (), "resolved impl block type {%u} to", + reference); + + // this could be recursive to the root type + if (impl->has_type ()) + { + HIR::Type &ty = impl->get_type (); + NodeId ref_node_id = UNKNOWN_NODEID; + NodeId ast_node_id = ty.get_mappings ().get_nodeid (); + + if (flag_name_resolution_2_0) + { + auto &nr_ctx = Resolver2_0::ImmutableNameResolutionContext::get () + .resolver (); + + // assign the ref_node_id if we've found something + nr_ctx.lookup (ast_node_id) + .map ( + [&ref_node_id] (NodeId resolved) { ref_node_id = resolved; }); + } + else if (!resolver.lookup_resolved_name (ast_node_id, &ref_node_id)) + resolver.lookup_resolved_type (ast_node_id, &ref_node_id); + + if (ref_node_id != UNKNOWN_NODEID) + { + tl::optional<HirId> hid + = mappings.lookup_node_to_hir (ref_node_id); + if (hid.has_value () && context->query_in_progress (hid.value ())) + { + context->query_completed (reference); + return false; + } + } + } + + *result = TypeCheckItem::ResolveImplBlockSelf (*impl); context->query_completed (reference); return true; } @@ -99,8 +139,9 @@ query_type (HirId reference, TyTy::BaseType **result) auto block = mappings.lookup_hir_extern_block (extern_item->second); rust_assert (block.has_value ()); - *result = TypeCheckTopLevelExternItem::Resolve (extern_item->first, - *block.value ()); + *result + = TypeCheckTopLevelExternItem::Resolve (*extern_item.value ().first, + *block.value ()); context->query_completed (reference); return true; } @@ -216,8 +257,10 @@ coercion_site (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs, rust_debug ("coerce_default_unify(a={%s}, b={%s})", receiver->debug_str ().c_str (), expected->debug_str ().c_str ()); TyTy::BaseType *coerced - = unify_site (id, lhs, TyTy::TyWithLocation (receiver, rhs.get_locus ()), - locus); + = unify_site_and (id, lhs, + TyTy::TyWithLocation (receiver, rhs.get_locus ()), locus, + true /*emit_error*/, true /*commit*/, true /*infer*/, + true /*cleanup*/); context->insert_autoderef_mappings (id, std::move (result.adjustments)); return coerced; } diff --git a/gcc/rust/typecheck/rust-typecheck-context.cc b/gcc/rust/typecheck/rust-typecheck-context.cc index 8f7a8a4..9112b99 100644 --- a/gcc/rust/typecheck/rust-typecheck-context.cc +++ b/gcc/rust/typecheck/rust-typecheck-context.cc @@ -73,6 +73,12 @@ TypeCheckContext::insert_builtin (HirId id, NodeId ref, TyTy::BaseType *type) builtins.push_back (std::unique_ptr<TyTy::BaseType> (type)); } +const std::vector<std::unique_ptr<TyTy::BaseType>> & +TypeCheckContext::get_builtins () const +{ + return builtins; +} + void TypeCheckContext::insert_type (const Analysis::NodeMapping &mappings, TyTy::BaseType *type) @@ -85,13 +91,6 @@ TypeCheckContext::insert_type (const Analysis::NodeMapping &mappings, } void -TypeCheckContext::insert_implicit_type (TyTy::BaseType *type) -{ - rust_assert (type != nullptr); - resolved[type->get_ref ()] = type; -} - -void TypeCheckContext::insert_implicit_type (HirId id, TyTy::BaseType *type) { rust_assert (type != nullptr); @@ -171,6 +170,12 @@ TypeCheckContext::peek_context () return return_type_stack.back ().first; } +StackedContexts<TypeCheckBlockContextItem> & +TypeCheckContext::block_context () +{ + return block_stack; +} + void TypeCheckContext::iterate (std::function<bool (HirId, TyTy::BaseType *)> cb) { @@ -243,23 +248,6 @@ TypeCheckContext::lookup_trait_reference (DefId id, TraitReference **ref) } void -TypeCheckContext::insert_receiver (HirId id, TyTy::BaseType *t) -{ - receiver_context[id] = t; -} - -bool -TypeCheckContext::lookup_receiver (HirId id, TyTy::BaseType **ref) -{ - auto it = receiver_context.find (id); - if (it == receiver_context.end ()) - return false; - - *ref = it->second; - return true; -} - -void TypeCheckContext::insert_associated_trait_impl ( HirId id, AssociatedImplTrait &&associated) { @@ -526,7 +514,16 @@ TypeCheckContext::lookup_lifetime (const HIR::Lifetime &lifetime) const { if (lifetime.get_lifetime_type () == AST::Lifetime::NAMED) { - rust_assert (lifetime.get_name () != "static"); + if (lifetime.get_name () == "static") + { + rich_location r (line_table, lifetime.get_locus ()); + r.add_fixit_insert_after (lifetime.get_locus (), + "static is a reserved lifetime name"); + rust_error_at (r, ErrorCode::E0262, + "invalid lifetime parameter name: %qs", + lifetime.get_name ().c_str ()); + return tl::nullopt; + } const auto name = lifetime.get_name (); auto it = lifetime_name_interner.find (name); if (it == lifetime_name_interner.end ()) @@ -640,9 +637,9 @@ TypeCheckContextItem::TypeCheckContextItem (HIR::Function *item) : type (ItemType::ITEM), item (item) {} -TypeCheckContextItem::TypeCheckContextItem (HIR::ImplBlock *impl_block, +TypeCheckContextItem::TypeCheckContextItem (HIR::ImplBlock &impl_block, HIR::Function *item) - : type (ItemType::IMPL_ITEM), item (impl_block, item) + : type (ItemType::IMPL_ITEM), item (&impl_block, item) {} TypeCheckContextItem::TypeCheckContextItem (HIR::TraitItemFunc *trait_item) @@ -796,5 +793,43 @@ TypeCheckContextItem::get_defid () const return UNKNOWN_DEFID; } +// TypeCheckBlockContextItem + +TypeCheckBlockContextItem::Item::Item (HIR::ImplBlock *b) : block (b) {} + +TypeCheckBlockContextItem::Item::Item (HIR::Trait *t) : trait (t) {} + +TypeCheckBlockContextItem::TypeCheckBlockContextItem (HIR::ImplBlock *block) + : type (TypeCheckBlockContextItem::ItemType::IMPL_BLOCK), item (block) +{} + +TypeCheckBlockContextItem::TypeCheckBlockContextItem (HIR::Trait *trait) + : type (TypeCheckBlockContextItem::ItemType::TRAIT), item (trait) +{} + +bool +TypeCheckBlockContextItem::is_impl_block () const +{ + return type == IMPL_BLOCK; +} + +bool +TypeCheckBlockContextItem::is_trait_block () const +{ + return type == TRAIT; +} + +HIR::ImplBlock & +TypeCheckBlockContextItem::get_impl_block () +{ + return *(item.block); +} + +HIR::Trait & +TypeCheckBlockContextItem::get_trait () +{ + return *(item.trait); +} + } // namespace Resolver } // namespace Rust diff --git a/gcc/rust/typecheck/rust-tyty-bounds.cc b/gcc/rust/typecheck/rust-tyty-bounds.cc index b73e592..e028a0a 100644 --- a/gcc/rust/typecheck/rust-tyty-bounds.cc +++ b/gcc/rust/typecheck/rust-tyty-bounds.cc @@ -16,9 +16,11 @@ // along with GCC; see the file COPYING3. If not see // <http://www.gnu.org/licenses/>. +#include "rust-hir-full-decls.h" #include "rust-hir-type-bounds.h" #include "rust-hir-trait-resolve.h" #include "rust-substitution-mapper.h" +#include "rust-hir-trait-resolve.h" #include "rust-type-util.h" namespace Rust { @@ -70,7 +72,15 @@ TypeBoundsProbe::scan () if (!impl->has_trait_ref ()) return true; - HirId impl_ty_id = impl->get_type ()->get_mappings ().get_hirid (); + // can be recursive trait resolution + HIR::Trait *t = TraitResolver::ResolveHirItem (impl->get_trait_ref ()); + if (t == nullptr) + return true; + DefId trait_id = t->get_mappings ().get_defid (); + if (context->trait_query_in_progress (trait_id)) + return true; + + HirId impl_ty_id = impl->get_type ().get_mappings ().get_hirid (); TyTy::BaseType *impl_type = nullptr; if (!query_type (impl_ty_id, &impl_type)) return true; @@ -81,7 +91,7 @@ TypeBoundsProbe::scan () return true; } - possible_trait_paths.push_back ({impl->get_trait_ref ().get (), impl}); + possible_trait_paths.push_back ({&impl->get_trait_ref (), impl}); return true; }); @@ -96,6 +106,10 @@ TypeBoundsProbe::scan () // marker traits... assemble_sized_builtin (); + + // add auto trait bounds + for (auto *auto_trait : mappings.get_auto_traits ()) + add_trait_bound (auto_trait); } void @@ -131,6 +145,7 @@ TypeBoundsProbe::assemble_sized_builtin () case TyTy::NEVER: case TyTy::PLACEHOLDER: case TyTy::PROJECTION: + case TyTy::OPAQUE: assemble_builtin_candidate (LangItem::Kind::SIZED); break; @@ -150,6 +165,14 @@ TypeBoundsProbe::assemble_sized_builtin () } void +TypeBoundsProbe::add_trait_bound (HIR::Trait *trait) +{ + auto trait_ref = TraitResolver::Resolve (*trait); + + trait_references.push_back ({trait_ref, mappings.lookup_builtin_marker ()}); +} + +void TypeBoundsProbe::assemble_builtin_candidate (LangItem::Kind lang_item) { auto lang_item_defined = mappings.lookup_lang_item (lang_item); @@ -166,9 +189,7 @@ TypeBoundsProbe::assemble_builtin_candidate (LangItem::Kind lang_item) HIR::Trait *trait = static_cast<HIR::Trait *> (item); const TyTy::BaseType *raw = receiver->destructure (); - // assemble the reference - TraitReference *trait_ref = TraitResolver::Resolve (*trait); - trait_references.push_back ({trait_ref, mappings.lookup_builtin_marker ()}); + add_trait_bound (trait); rust_debug ("Added builtin lang_item: %s for %s", LangItem::ToString (lang_item).c_str (), @@ -182,9 +203,10 @@ TypeCheckBase::resolve_trait_path (HIR::TypePath &path) } TyTy::TypeBoundPredicate -TypeCheckBase::get_predicate_from_bound (HIR::TypePath &type_path, - HIR::Type *associated_self, - BoundPolarity polarity) +TypeCheckBase::get_predicate_from_bound ( + HIR::TypePath &type_path, + tl::optional<std::reference_wrapper<HIR::Type>> associated_self, + BoundPolarity polarity, bool is_qualified_type_path) { TyTy::TypeBoundPredicate lookup = TyTy::TypeBoundPredicate::error (); bool already_resolved @@ -202,29 +224,44 @@ TypeCheckBase::get_predicate_from_bound (HIR::TypePath &type_path, = HIR::GenericArgs::create_empty (type_path.get_locus ()); auto &final_seg = type_path.get_final_segment (); - switch (final_seg->get_type ()) + switch (final_seg.get_type ()) { case HIR::TypePathSegment::SegmentType::GENERIC: { - auto final_generic_seg - = static_cast<HIR::TypePathSegmentGeneric *> (final_seg.get ()); - if (final_generic_seg->has_generic_args ()) + auto &final_generic_seg + = static_cast<HIR::TypePathSegmentGeneric &> (final_seg); + if (final_generic_seg.has_generic_args ()) { - args = final_generic_seg->get_generic_args (); + args = final_generic_seg.get_generic_args (); + if (args.get_binding_args ().size () > 0 + && associated_self.has_value () && is_qualified_type_path) + { + auto &binding_args = args.get_binding_args (); + + rich_location r (line_table, args.get_locus ()); + for (auto it = binding_args.begin (); it != binding_args.end (); + it++) + { + auto &arg = *it; + r.add_fixit_remove (arg.get_locus ()); + } + rust_error_at (r, ErrorCode::E0229, + "associated type bindings are not allowed here"); + } } } break; case HIR::TypePathSegment::SegmentType::FUNCTION: { - auto final_function_seg - = static_cast<HIR::TypePathSegmentFunction *> (final_seg.get ()); - auto &fn = final_function_seg->get_function_path (); + auto &final_function_seg + = static_cast<HIR::TypePathSegmentFunction &> (final_seg); + auto &fn = final_function_seg.get_function_path (); // we need to make implicit generic args which must be an implicit // Tuple auto crate_num = mappings.get_current_crate (); HirId implicit_args_id = mappings.get_next_hir_id (); Analysis::NodeMapping mapping (crate_num, - final_seg->get_mappings ().get_nodeid (), + final_seg.get_mappings ().get_nodeid (), implicit_args_id, UNKNOWN_LOCAL_DEFID); std::vector<std::unique_ptr<HIR::Type>> params_copy; @@ -233,36 +270,34 @@ TypeCheckBase::get_predicate_from_bound (HIR::TypePath &type_path, params_copy.push_back (p->clone_type ()); } - HIR::TupleType *implicit_tuple - = new HIR::TupleType (mapping, std::move (params_copy), - final_seg->get_locus ()); - std::vector<std::unique_ptr<HIR::Type>> inputs; - inputs.push_back (std::unique_ptr<HIR::Type> (implicit_tuple)); + inputs.push_back ( + std::make_unique<HIR::TupleType> (mapping, std::move (params_copy), + final_seg.get_locus ())); // resolve the fn_once_output type which assumes there must be an output // set rust_assert (fn.has_return_type ()); - TypeCheckType::Resolve (fn.get_return_type ().get ()); + TypeCheckType::Resolve (fn.get_return_type ()); HIR::TraitItem *trait_item = mappings .lookup_trait_item_lang_item (LangItem::Kind::FN_ONCE_OUTPUT, - final_seg->get_locus ()) + final_seg.get_locus ()) .value (); std::vector<HIR::GenericArgsBinding> bindings; - location_t output_locus = fn.get_return_type ()->get_locus (); + location_t output_locus = fn.get_return_type ().get_locus (); HIR::GenericArgsBinding binding (Identifier ( trait_item->trait_identifier ()), - fn.get_return_type ()->clone_type (), + fn.get_return_type ().clone_type (), output_locus); bindings.push_back (std::move (binding)); args = HIR::GenericArgs ({} /* lifetimes */, std::move (inputs) /* type_args*/, std::move (bindings) /* binding_args*/, - {} /* const_args */, final_seg->get_locus ()); + {} /* const_args */, final_seg.get_locus ()); } break; @@ -271,11 +306,11 @@ TypeCheckBase::get_predicate_from_bound (HIR::TypePath &type_path, break; } - if (associated_self != nullptr) + if (associated_self.has_value ()) { std::vector<std::unique_ptr<HIR::Type>> type_args; - type_args.push_back ( - std::unique_ptr<HIR::Type> (associated_self->clone_type ())); + type_args.push_back (std::unique_ptr<HIR::Type> ( + associated_self.value ().get ().clone_type ())); for (auto &arg : args.get_type_args ()) { type_args.push_back (std::unique_ptr<HIR::Type> (arg->clone_type ())); @@ -292,7 +327,7 @@ TypeCheckBase::get_predicate_from_bound (HIR::TypePath &type_path, if (!args.is_empty () || predicate.requires_generic_args ()) { // this is applying generic arguments to a trait reference - predicate.apply_generic_arguments (&args, associated_self != nullptr); + predicate.apply_generic_arguments (&args, associated_self.has_value ()); } context->insert_resolved_predicate (type_path.get_mappings ().get_hirid (), @@ -310,7 +345,8 @@ TypeBoundPredicate::TypeBoundPredicate ( location_t locus) : SubstitutionRef ({}, SubstitutionArgumentMappings::empty (), {}), reference (trait_reference.get_mappings ().get_defid ()), locus (locus), - error_flag (false), polarity (polarity) + error_flag (false), polarity (polarity), + super_traits (trait_reference.get_super_traits ()) { rust_assert (!trait_reference.get_trait_substs ().empty ()); @@ -350,7 +386,8 @@ TypeBoundPredicate::TypeBoundPredicate (mark_is_error) TypeBoundPredicate::TypeBoundPredicate (const TypeBoundPredicate &other) : SubstitutionRef ({}, SubstitutionArgumentMappings::empty (), {}), reference (other.reference), locus (other.locus), - error_flag (other.error_flag), polarity (other.polarity) + error_flag (other.error_flag), polarity (other.polarity), + super_traits (other.super_traits) { substitutions.clear (); for (const auto &p : other.get_substs ()) @@ -420,6 +457,7 @@ TypeBoundPredicate::operator= (const TypeBoundPredicate &other) = SubstitutionArgumentMappings (copied_arg_mappings, {}, other.used_arguments.get_regions (), other.used_arguments.get_locus ()); + super_traits = other.super_traits; return *this; } @@ -486,11 +524,19 @@ TypeBoundPredicate::apply_generic_arguments (HIR::GenericArgs *generic_args, } // now actually perform a substitution - used_arguments = get_mappings_from_generic_args ( + auto args = get_mappings_from_generic_args ( *generic_args, Resolver::TypeCheckContext::get ()->regions_from_generic_args ( *generic_args)); + apply_argument_mappings (args); +} + +void +TypeBoundPredicate::apply_argument_mappings ( + SubstitutionArgumentMappings &arguments) +{ + used_arguments = arguments; error_flag |= used_arguments.is_error (); auto &subst_mappings = used_arguments; for (auto &sub : get_substs ()) @@ -514,6 +560,14 @@ TypeBoundPredicate::apply_generic_arguments (HIR::GenericArgs *generic_args, const auto item_ref = item.get_raw_item (); item_ref->associated_type_set (type); } + + for (auto &super_trait : super_traits) + { + auto adjusted + = super_trait.adjust_mappings_for_this (used_arguments, + true /*trait mode*/); + super_trait.apply_argument_mappings (adjusted); + } } bool @@ -529,34 +583,56 @@ TypeBoundPredicate::lookup_associated_item (const std::string &search) const { auto trait_ref = get (); const Resolver::TraitItemReference *trait_item_ref = nullptr; - if (!trait_ref->lookup_trait_item (search, &trait_item_ref)) - return TypeBoundPredicateItem::error (); + if (trait_ref->lookup_trait_item (search, &trait_item_ref, + false /*lookup supers*/)) + return TypeBoundPredicateItem (*this, trait_item_ref); - return TypeBoundPredicateItem (this, trait_item_ref); + for (auto &super_trait : super_traits) + { + auto lookup = super_trait.lookup_associated_item (search); + if (!lookup.is_error ()) + return lookup; + } + + return TypeBoundPredicateItem::error (); } TypeBoundPredicateItem::TypeBoundPredicateItem ( - const TypeBoundPredicate *parent, + const TypeBoundPredicate parent, const Resolver::TraitItemReference *trait_item_ref) : parent (parent), trait_item_ref (trait_item_ref) {} +TypeBoundPredicateItem::TypeBoundPredicateItem ( + const TypeBoundPredicateItem &other) + : parent (other.parent), trait_item_ref (other.trait_item_ref) +{} + +TypeBoundPredicateItem & +TypeBoundPredicateItem::operator= (const TypeBoundPredicateItem &other) +{ + parent = other.parent; + trait_item_ref = other.trait_item_ref; + + return *this; +} + TypeBoundPredicateItem TypeBoundPredicateItem::error () { - return TypeBoundPredicateItem (nullptr, nullptr); + return TypeBoundPredicateItem (TypeBoundPredicate::error (), nullptr); } bool TypeBoundPredicateItem::is_error () const { - return parent == nullptr || trait_item_ref == nullptr; + return parent.is_error () || trait_item_ref == nullptr; } const TypeBoundPredicate * TypeBoundPredicateItem::get_parent () const { - return parent; + return &parent; } TypeBoundPredicateItem @@ -570,7 +646,7 @@ BaseType * TypeBoundPredicateItem::get_tyty_for_receiver (const TyTy::BaseType *receiver) { TyTy::BaseType *trait_item_tyty = get_raw_item ()->get_tyty (); - if (parent->get_substitution_arguments ().is_empty ()) + if (parent.get_substitution_arguments ().is_empty ()) return trait_item_tyty; const Resolver::TraitItemReference *tref = get_raw_item (); @@ -579,7 +655,7 @@ TypeBoundPredicateItem::get_tyty_for_receiver (const TyTy::BaseType *receiver) return trait_item_tyty; // set up the self mapping - SubstitutionArgumentMappings gargs = parent->get_substitution_arguments (); + SubstitutionArgumentMappings gargs = parent.get_substitution_arguments (); rust_assert (!gargs.is_empty ()); // setup the adjusted mappings @@ -711,7 +787,7 @@ TypeBoundPredicate::get_associated_type_items () == Resolver::TraitItemReference::TraitItemType::TYPE; if (is_associated_type) { - TypeBoundPredicateItem item (this, &trait_item); + TypeBoundPredicateItem item (*this, &trait_item); items.push_back (std::move (item)); } } @@ -752,6 +828,65 @@ TypeBoundPredicate::is_equal (const TypeBoundPredicate &other) const return true; } +bool +TypeBoundPredicate::validate_type_implements_super_traits ( + TyTy::BaseType &self, HIR::Type &impl_type, HIR::Type &trait) const +{ + if (get_polarity () != BoundPolarity::RegularBound) + return true; + + auto &ptref = *get (); + for (auto &super : super_traits) + { + if (super.get_polarity () != BoundPolarity::RegularBound) + continue; + + if (!super.validate_type_implements_this (self, impl_type, trait)) + { + auto &sptref = *super.get (); + + // emit error + std::string fixit1 + = "required by this bound in: " + ptref.get_name (); + std::string fixit2 = "the trait " + sptref.get_name () + + " is not implemented for " + + impl_type.as_string (); + + rich_location r (line_table, trait.get_locus ()); + r.add_fixit_insert_after (super.get_locus (), fixit1.c_str ()); + r.add_fixit_insert_after (trait.get_locus (), fixit2.c_str ()); + rust_error_at (r, ErrorCode::E0277, + "the trait bound %<%s: %s%> is not satisfied", + impl_type.as_string ().c_str (), + sptref.get_name ().c_str ()); + + return false; + } + + if (!super.validate_type_implements_super_traits (self, impl_type, trait)) + return false; + } + + return true; +} + +bool +TypeBoundPredicate::validate_type_implements_this (TyTy::BaseType &self, + HIR::Type &impl_type, + HIR::Type &trait) const +{ + const auto &ptref = *get (); + auto probed_bounds = Resolver::TypeBoundsProbe::Probe (&self); + for (auto &elem : probed_bounds) + { + auto &tref = *(elem.first); + if (ptref.is_equal (tref)) + return true; + } + + return false; +} + // trait item reference const Resolver::TraitItemReference * diff --git a/gcc/rust/typecheck/rust-tyty-bounds.h b/gcc/rust/typecheck/rust-tyty-bounds.h index be309b2..6392af1 100644 --- a/gcc/rust/typecheck/rust-tyty-bounds.h +++ b/gcc/rust/typecheck/rust-tyty-bounds.h @@ -34,31 +34,6 @@ namespace TyTy { class BaseType; class TypeBoundPredicate; -class TypeBoundPredicateItem -{ -public: - TypeBoundPredicateItem (const TypeBoundPredicate *parent, - const Resolver::TraitItemReference *trait_item_ref); - - static TypeBoundPredicateItem error (); - - bool is_error () const; - - BaseType *get_tyty_for_receiver (const TyTy::BaseType *receiver); - - const Resolver::TraitItemReference *get_raw_item () const; - - bool needs_implementation () const; - - const TypeBoundPredicate *get_parent () const; - - location_t get_locus () const; - -private: - const TypeBoundPredicate *parent; - const Resolver::TraitItemReference *trait_item_ref; -}; - class TypeBoundsMappings { protected: diff --git a/gcc/rust/typecheck/rust-tyty-call.cc b/gcc/rust/typecheck/rust-tyty-call.cc index ad3b2c3..2e0830e 100644 --- a/gcc/rust/typecheck/rust-tyty-call.cc +++ b/gcc/rust/typecheck/rust-tyty-call.cc @@ -80,7 +80,7 @@ TypeCheckCallExpr::visit (ADTType &type) BaseType *field_tyty = field->get_field_type (); location_t arg_locus = argument->get_locus (); - BaseType *arg = Resolver::TypeCheckExpr::Resolve (argument.get ()); + BaseType *arg = Resolver::TypeCheckExpr::Resolve (*argument); if (arg->get_kind () == TyTy::TypeKind::ERROR) { rust_error_at (argument->get_locus (), @@ -139,26 +139,19 @@ TypeCheckCallExpr::visit (FnType &type) for (auto &argument : call.get_arguments ()) { location_t arg_locus = argument->get_locus (); - auto argument_expr_tyty - = Resolver::TypeCheckExpr::Resolve (argument.get ()); - if (argument_expr_tyty->get_kind () == TyTy::TypeKind::ERROR) - { - rust_error_at ( - argument->get_locus (), - "failed to resolve type for argument expr in CallExpr"); - return; - } + auto argument_expr_tyty = Resolver::TypeCheckExpr::Resolve (*argument); + if (argument_expr_tyty->is<TyTy::ErrorType> ()) + return; // it might be a variadic function if (i < type.num_params ()) { - auto fnparam = type.param_at (i); - HIR::Pattern *fn_param_pattern = fnparam.first; - BaseType *param_ty = fnparam.second; + auto &fnparam = type.param_at (i); + BaseType *param_ty = fnparam.get_type (); location_t param_locus - = fn_param_pattern == nullptr - ? mappings.lookup_location (param_ty->get_ref ()) - : fn_param_pattern->get_locus (); + = fnparam.has_pattern () + ? fnparam.get_pattern ().get_locus () + : mappings.lookup_location (param_ty->get_ref ()); HirId coercion_side_id = argument->get_mappings ().get_hirid (); auto resolved_argument_type @@ -272,8 +265,7 @@ TypeCheckCallExpr::visit (FnPtr &type) { location_t arg_locus = argument->get_locus (); BaseType *fnparam = type.get_param_type_at (i); - auto argument_expr_tyty - = Resolver::TypeCheckExpr::Resolve (argument.get ()); + auto argument_expr_tyty = Resolver::TypeCheckExpr::Resolve (*argument); if (argument_expr_tyty->get_kind () == TyTy::TypeKind::ERROR) { rust_error_at ( @@ -322,8 +314,7 @@ TypeCheckMethodCallExpr::go (FnType *ref, HIR::MethodCallExpr &call, std::vector<Argument> args; for (auto &arg : call.get_arguments ()) { - BaseType *argument_expr_tyty - = Resolver::TypeCheckExpr::Resolve (arg.get ()); + BaseType *argument_expr_tyty = Resolver::TypeCheckExpr::Resolve (*arg); if (argument_expr_tyty->get_kind () == TyTy::TypeKind::ERROR) { rust_error_at (arg->get_locus (), @@ -337,7 +328,7 @@ TypeCheckMethodCallExpr::go (FnType *ref, HIR::MethodCallExpr &call, TypeCheckMethodCallExpr checker (call.get_mappings (), args, call.get_locus (), - call.get_receiver ()->get_locus (), + call.get_receiver ().get_locus (), adjusted_self, context); return checker.check (*ref); } @@ -377,13 +368,12 @@ TypeCheckMethodCallExpr::check (FnType &type) { location_t arg_locus = argument.get_locus (); - auto fnparam = type.param_at (i); - HIR::Pattern *fn_param_pattern = fnparam.first; - BaseType *param_ty = fnparam.second; + auto &fnparam = type.param_at (i); + BaseType *param_ty = fnparam.get_type (); location_t param_locus - = fn_param_pattern == nullptr - ? mappings.lookup_location (param_ty->get_ref ()) - : fn_param_pattern->get_locus (); + = fnparam.has_pattern () + ? fnparam.get_pattern ().get_locus () + : mappings.lookup_location (param_ty->get_ref ()); auto argument_expr_tyty = argument.get_argument_type (); HirId coercion_side_id = argument.get_mappings ().get_hirid (); diff --git a/gcc/rust/typecheck/rust-tyty-call.h b/gcc/rust/typecheck/rust-tyty-call.h index 67cfe30..c42fdcd 100644 --- a/gcc/rust/typecheck/rust-tyty-call.h +++ b/gcc/rust/typecheck/rust-tyty-call.h @@ -61,6 +61,7 @@ public: void visit (ProjectionType &) override { rust_unreachable (); } void visit (DynamicObjectType &) override { rust_unreachable (); } void visit (ClosureType &type) override { rust_unreachable (); } + void visit (OpaqueType &type) override { rust_unreachable (); } // tuple-structs void visit (ADTType &type) override; @@ -73,14 +74,12 @@ private: TypeCheckCallExpr (HIR::CallExpr &c, TyTy::VariantDef &variant, Resolver::TypeCheckContext *context) : resolved (new TyTy::ErrorType (c.get_mappings ().get_hirid ())), call (c), - variant (variant), context (context), - mappings (Analysis::Mappings::get ()) + variant (variant), mappings (Analysis::Mappings::get ()) {} BaseType *resolved; HIR::CallExpr &call; TyTy::VariantDef &variant; - Resolver::TypeCheckContext *context; Analysis::Mappings &mappings; }; diff --git a/gcc/rust/typecheck/rust-tyty-cmp.h b/gcc/rust/typecheck/rust-tyty-cmp.h index c384287..c897c13 100644 --- a/gcc/rust/typecheck/rust-tyty-cmp.h +++ b/gcc/rust/typecheck/rust-tyty-cmp.h @@ -431,6 +431,22 @@ public: } } + virtual void visit (const OpaqueType &type) override + { + ok = false; + if (emit_error_flag) + { + location_t ref_locus = mappings.lookup_location (type.get_ref ()); + location_t base_locus + = mappings.lookup_location (get_base ()->get_ref ()); + rich_location r (line_table, ref_locus); + r.add_range (base_locus); + rust_error_at (r, "expected [%s] got [%s]", + get_base ()->as_string ().c_str (), + type.as_string ().c_str ()); + } + } + protected: BaseCmp (const BaseType *base, bool emit_errors) : mappings (Analysis::Mappings::get ()), @@ -735,8 +751,8 @@ public: for (size_t i = 0; i < base->num_params (); i++) { - auto a = base->param_at (i).second; - auto b = type.param_at (i).second; + auto a = base->param_at (i).get_type (); + auto b = type.param_at (i).get_type (); if (!a->can_eq (b, emit_error_flag)) { @@ -831,7 +847,7 @@ public: for (size_t i = 0; i < base->num_params (); i++) { auto this_param = base->get_param_type_at (i); - auto other_param = type.param_at (i).second; + auto other_param = type.param_at (i).get_type (); if (!this_param->can_eq (other_param, emit_error_flag)) { BaseCmp::visit (type); @@ -1571,6 +1587,23 @@ private: const DynamicObjectType *base; }; +class OpaqueCmp : public BaseCmp +{ + using Rust::TyTy::BaseCmp::visit; + +public: + OpaqueCmp (const OpaqueType *base, bool emit_errors) + : BaseCmp (base, emit_errors), base (base) + {} + + // TODO + +private: + const BaseType *get_base () const override { return base; } + + const OpaqueType *base; +}; + } // namespace TyTy } // namespace Rust diff --git a/gcc/rust/typecheck/rust-tyty-subst.cc b/gcc/rust/typecheck/rust-tyty-subst.cc index a3ebf0a..bdb6474 100644 --- a/gcc/rust/typecheck/rust-tyty-subst.cc +++ b/gcc/rust/typecheck/rust-tyty-subst.cc @@ -28,8 +28,8 @@ namespace Rust { namespace TyTy { -SubstitutionParamMapping::SubstitutionParamMapping ( - const HIR::TypeParam &generic, ParamType *param) +SubstitutionParamMapping::SubstitutionParamMapping (HIR::TypeParam &generic, + ParamType *param) : generic (generic), param (param) {} @@ -66,8 +66,8 @@ SubstitutionParamMapping::get_param_ty () const return param; } -const HIR::TypeParam & -SubstitutionParamMapping::get_generic_param () const +HIR::TypeParam & +SubstitutionParamMapping::get_generic_param () { return generic; } @@ -630,12 +630,10 @@ SubstitutionRef::get_mappings_from_generic_args ( for (auto &binding : args.get_binding_args ()) { BaseType *resolved - = Resolver::TypeCheckType::Resolve (binding.get_type ().get ()); + = Resolver::TypeCheckType::Resolve (binding.get_type ()); if (resolved == nullptr || resolved->get_kind () == TyTy::TypeKind::ERROR) { - rust_error_at (binding.get_locus (), - "failed to resolve type arguments"); return SubstitutionArgumentMappings::error (); } @@ -698,10 +696,9 @@ SubstitutionRef::get_mappings_from_generic_args ( std::vector<SubstitutionArg> mappings = used_arguments.get_mappings (); for (auto &arg : args.get_type_args ()) { - BaseType *resolved = Resolver::TypeCheckType::Resolve (arg.get ()); + BaseType *resolved = Resolver::TypeCheckType::Resolve (*arg); if (resolved == nullptr || resolved->get_kind () == TyTy::TypeKind::ERROR) { - rust_error_at (args.get_locus (), "failed to resolve type arguments"); return SubstitutionArgumentMappings::error (); } @@ -791,7 +788,7 @@ SubstitutionRef::infer_substitions (location_t locus) SubstitutionArgumentMappings SubstitutionRef::adjust_mappings_for_this ( - SubstitutionArgumentMappings &mappings) + SubstitutionArgumentMappings &mappings, bool trait_mode) { std::vector<SubstitutionArg> resolved_mappings; for (size_t i = 0; i < substitutions.size (); i++) @@ -819,7 +816,7 @@ SubstitutionRef::adjust_mappings_for_this ( } bool ok = !arg.is_error (); - if (ok) + if (ok || (trait_mode && i == 0)) { SubstitutionArg adjusted (&subst, arg.get_tyty ()); resolved_mappings.push_back (std::move (adjusted)); @@ -937,27 +934,8 @@ SubstitutionRef::monomorphize () auto associated = Resolver::lookup_associated_impl_block (bound, binding, &ambigious); - if (associated == nullptr && ambigious) - { - // go for the first one? or error out? - auto &mappings = Analysis::Mappings::get (); - const auto &type_param = subst.get_generic_param (); - const auto *trait_ref = bound.get (); - - rich_location r (line_table, type_param.get_locus ()); - r.add_range (bound.get_locus ()); - r.add_range (mappings.lookup_location (binding->get_ref ())); - - rust_error_at (r, "ambiguous type bound for trait %s and type %s", - trait_ref->get_name ().c_str (), - binding->get_name ().c_str ()); - return false; - } - if (associated != nullptr) - { - associated->setup_associated_types (binding, bound); - } + associated->setup_associated_types (binding, bound); } } diff --git a/gcc/rust/typecheck/rust-tyty-subst.h b/gcc/rust/typecheck/rust-tyty-subst.h index ab53502..e6ed1fc 100644 --- a/gcc/rust/typecheck/rust-tyty-subst.h +++ b/gcc/rust/typecheck/rust-tyty-subst.h @@ -44,7 +44,7 @@ class SubstitutionArgumentMappings; class SubstitutionParamMapping { public: - SubstitutionParamMapping (const HIR::TypeParam &generic, ParamType *param); + SubstitutionParamMapping (HIR::TypeParam &generic, ParamType *param); SubstitutionParamMapping (const SubstitutionParamMapping &other); @@ -59,7 +59,7 @@ public: const ParamType *get_param_ty () const; - const HIR::TypeParam &get_generic_param () const; + HIR::TypeParam &get_generic_param (); // this is used for the backend to override the HirId ref of the param to // what the concrete type is for the rest of the context @@ -76,7 +76,7 @@ public: bool need_substitution () const; private: - const HIR::TypeParam &generic; + HIR::TypeParam &generic; ParamType *param; }; @@ -125,7 +125,7 @@ public: std::vector<Region> subst) { RegionParamList list (num_regions); - for (size_t i = 0; i < subst.size (); i++) + for (size_t i = 0; i < MIN (num_regions, subst.size ()); i++) list.regions.at (i) = subst.at (i); for (size_t i = subst.size (); i < num_regions; i++) { @@ -253,6 +253,7 @@ private: bool error_flag; }; +class TypeBoundPredicateItem; class SubstitutionRef { public: @@ -319,7 +320,8 @@ public: // we have bindings for X Y Z and need to propagate the binding Y,Z into Foo // Which binds to A,B SubstitutionArgumentMappings - adjust_mappings_for_this (SubstitutionArgumentMappings &mappings); + adjust_mappings_for_this (SubstitutionArgumentMappings &mappings, + bool trait_mode = false); // Are the mappings here actually bound to this type. For example imagine the // case: diff --git a/gcc/rust/typecheck/rust-tyty-variance-analysis-private.h b/gcc/rust/typecheck/rust-tyty-variance-analysis-private.h index 41a0d6f..d36afc8 100644 --- a/gcc/rust/typecheck/rust-tyty-variance-analysis-private.h +++ b/gcc/rust/typecheck/rust-tyty-variance-analysis-private.h @@ -168,6 +168,8 @@ public: { // TODO } + + void visit (OpaqueType &type) override {} }; /** Per crate context for generic type variance analysis. */ @@ -201,10 +203,9 @@ public: // Module internal API std::vector<Variance> query_generic_variance (const ADTType &type); - std::vector<size_t> query_field_regions (const ADTType *parent, - size_t variant_index, - size_t field_index, - const FreeRegions &parent_regions); + FreeRegions query_field_regions (const ADTType *parent, size_t variant_index, + size_t field_index, + const FreeRegions &parent_regions); std::vector<Region> query_type_regions (BaseType *base); @@ -309,7 +310,7 @@ class FieldVisitorCtx : public VarianceVisitorCtx<Variance> public: using Visitor = VisitorBase<Variance>; - std::vector<size_t> collect_regions (BaseType &ty); + FreeRegions collect_regions (BaseType &ty); FieldVisitorCtx (GenericTyPerCrateCtx &ctx, const SubstitutionRef &subst, const FreeRegions &parent_regions) @@ -332,7 +333,7 @@ public: private: GenericTyPerCrateCtx &ctx; const SubstitutionRef &subst; - std::vector<size_t> regions; + FreeRegions regions; FreeRegions parent_regions; std::vector<size_t> type_param_ranges; }; diff --git a/gcc/rust/typecheck/rust-tyty-variance-analysis.cc b/gcc/rust/typecheck/rust-tyty-variance-analysis.cc index d7116f5..38f9d52 100644 --- a/gcc/rust/typecheck/rust-tyty-variance-analysis.cc +++ b/gcc/rust/typecheck/rust-tyty-variance-analysis.cc @@ -52,7 +52,7 @@ CrateCtx::query_type_regions (BaseType *type) return private_ctx->query_type_regions (type); } -std::vector<size_t> +FreeRegions CrateCtx::query_field_regions (const ADTType *parent, size_t variant_index, size_t field_index, const FreeRegions &parent_regions) @@ -238,7 +238,7 @@ GenericTyVisitorCtx::process_type (ADTType &ty) first_lifetime = lookup_or_add_type (ty.get_orig_ref ()); first_type = first_lifetime + ty.get_used_arguments ().get_regions ().size (); - for (const auto ¶m : ty.get_substs ()) + for (auto ¶m : ty.get_substs ()) param_names.push_back ( param.get_generic_param ().get_type_representation ().as_string ()); @@ -332,7 +332,7 @@ GenericTyPerCrateCtx::query_generic_variance (const ADTType &type) return result; } -std::vector<size_t> +FreeRegions GenericTyPerCrateCtx::query_field_regions (const ADTType *parent, size_t variant_index, size_t field_index, @@ -537,7 +537,7 @@ TyVisitorCtx::add_constraints_from_generic_args (HirId ref, } } -std::vector<size_t> +FreeRegions FieldVisitorCtx::collect_regions (BaseType &ty) { // Segment the regions into ranges for each type parameter. Type parameter @@ -621,4 +621,4 @@ Term::make_transform (Term lhs, Term rhs) } // namespace VarianceAnalysis } // namespace TyTy -} // namespace Rust
\ No newline at end of file +} // namespace Rust diff --git a/gcc/rust/typecheck/rust-tyty-variance-analysis.h b/gcc/rust/typecheck/rust-tyty-variance-analysis.h index 27e8d8b..9059a2f 100644 --- a/gcc/rust/typecheck/rust-tyty-variance-analysis.h +++ b/gcc/rust/typecheck/rust-tyty-variance-analysis.h @@ -33,10 +33,9 @@ public: /** Get regions mentioned in a type. */ std::vector<Region> query_type_regions (BaseType *type); - std::vector<size_t> query_field_regions (const ADTType *parent, - size_t variant_index, - size_t field_index, - const FreeRegions &parent_regions); + FreeRegions query_field_regions (const ADTType *parent, size_t variant_index, + size_t field_index, + const FreeRegions &parent_regions); private: std::unique_ptr<GenericTyPerCrateCtx> private_ctx; diff --git a/gcc/rust/typecheck/rust-tyty-visitor.h b/gcc/rust/typecheck/rust-tyty-visitor.h index 85726ff..4f8e785 100644 --- a/gcc/rust/typecheck/rust-tyty-visitor.h +++ b/gcc/rust/typecheck/rust-tyty-visitor.h @@ -51,6 +51,7 @@ public: virtual void visit (ProjectionType &type) = 0; virtual void visit (DynamicObjectType &type) = 0; virtual void visit (ClosureType &type) = 0; + virtual void visit (OpaqueType &type) = 0; }; class TyConstVisitor @@ -80,6 +81,7 @@ public: virtual void visit (const ProjectionType &type) = 0; virtual void visit (const DynamicObjectType &type) = 0; virtual void visit (const ClosureType &type) = 0; + virtual void visit (const OpaqueType &type) = 0; }; } // namespace TyTy diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc index b877c0c..f0f4a07 100644 --- a/gcc/rust/typecheck/rust-tyty.cc +++ b/gcc/rust/typecheck/rust-tyty.cc @@ -18,6 +18,7 @@ #include "rust-tyty.h" +#include "optional.h" #include "rust-tyty-visitor.h" #include "rust-hir-map.h" #include "rust-location.h" @@ -31,6 +32,7 @@ #include "rust-hir-type-bounds.h" #include "options.h" +#include "rust-system.h" namespace Rust { namespace TyTy { @@ -109,6 +111,9 @@ TypeKindFormat::to_string (TypeKind kind) case TypeKind::CLOSURE: return "Closure"; + case TypeKind::OPAQUE: + return "Opaque"; + case TypeKind::ERROR: return "ERROR"; } @@ -215,7 +220,7 @@ BaseType::is_unit () const case FLOAT: case USIZE: case ISIZE: - + case OPAQUE: case STR: case DYNAMIC: case ERROR: @@ -541,6 +546,17 @@ BaseType::destructure () const { x = p->get (); } + // else if (auto p = x->try_as<const OpaqueType> ()) + // { + // auto pr = p->resolve (); + + // rust_debug ("XXXXXX") + + // if (pr == x) + // return pr; + + // x = pr; + // } else { return x; @@ -593,9 +609,9 @@ BaseType::monomorphized_clone () const } else if (auto fn = x->try_as<const FnType> ()) { - std::vector<std::pair<HIR::Pattern *, BaseType *>> cloned_params; + std::vector<TyTy::FnParam> cloned_params; for (auto &p : fn->get_params ()) - cloned_params.push_back ({p.first, p.second->monomorphized_clone ()}); + cloned_params.push_back (p.monomorphized_clone ()); BaseType *retty = fn->get_return_type ()->monomorphized_clone (); return new FnType (fn->get_ref (), fn->get_ty_ref (), fn->get_id (), @@ -622,7 +638,7 @@ BaseType::monomorphized_clone () const for (auto &variant : adt->get_variants ()) cloned_variants.push_back (variant->monomorphized_clone ()); - return new ADTType (adt->get_ref (), adt->get_ty_ref (), + return new ADTType (adt->get_id (), adt->get_ref (), adt->get_ty_ref (), adt->get_identifier (), adt->ident, adt->get_adt_kind (), cloned_variants, adt->clone_substs (), adt->get_repr_options (), @@ -666,6 +682,91 @@ BaseType::debug () const debug_str ().c_str ()); } +const TyTy::BaseType * +BaseType::contains_infer () const +{ + const TyTy::BaseType *x = destructure (); + + if (auto fn = x->try_as<const FnType> ()) + { + for (const auto ¶m : fn->get_params ()) + { + auto infer = param.get_type ()->contains_infer (); + if (infer) + return infer; + } + return fn->get_return_type ()->contains_infer (); + } + else if (auto fn = x->try_as<const FnPtr> ()) + { + for (const auto ¶m : fn->get_params ()) + { + auto infer = param.get_tyty ()->contains_infer (); + if (infer) + return infer; + } + return fn->get_return_type ()->contains_infer (); + } + else if (auto adt = x->try_as<const ADTType> ()) + { + for (auto &variant : adt->get_variants ()) + { + bool is_num_variant + = variant->get_variant_type () == VariantDef::VariantType::NUM; + if (is_num_variant) + continue; + + for (auto &field : variant->get_fields ()) + { + const BaseType *field_type = field->get_field_type (); + auto infer = (field_type->contains_infer ()); + if (infer) + return infer; + } + } + return nullptr; + } + else if (auto arr = x->try_as<const ArrayType> ()) + { + return arr->get_element_type ()->contains_infer (); + } + else if (auto slice = x->try_as<const SliceType> ()) + { + return slice->get_element_type ()->contains_infer (); + } + else if (auto ptr = x->try_as<const PointerType> ()) + { + return ptr->get_base ()->contains_infer (); + } + else if (auto ref = x->try_as<const ReferenceType> ()) + { + return ref->get_base ()->contains_infer (); + } + else if (auto tuple = x->try_as<const TupleType> ()) + { + for (size_t i = 0; i < tuple->num_fields (); i++) + { + auto infer = (tuple->get_field (i)->contains_infer ()); + if (infer) + return infer; + } + return nullptr; + } + else if (auto closure = x->try_as<const ClosureType> ()) + { + auto infer = (closure->get_parameters ().contains_infer ()); + if (infer) + return infer; + return closure->get_result_type ().contains_infer (); + } + else if (x->is<InferType> ()) + { + return x; + } + + return nullptr; +} + bool BaseType::is_concrete () const { @@ -686,7 +787,7 @@ BaseType::is_concrete () const { for (const auto ¶m : fn->get_params ()) { - if (!param.second->is_concrete ()) + if (!param.get_type ()->is_concrete ()) return false; } return fn->get_return_type ()->is_concrete (); @@ -790,6 +891,7 @@ BaseType::has_substitutions_defined () const case TUPLE: case PARAM: case PLACEHOLDER: + case OPAQUE: return false; case PROJECTION: { @@ -851,6 +953,7 @@ BaseType::needs_generic_substitutions () const case TUPLE: case PARAM: case PLACEHOLDER: + case OPAQUE: return false; case PROJECTION: { @@ -886,6 +989,48 @@ BaseType::needs_generic_substitutions () const return false; } +const SubstitutionArgumentMappings & +BaseType::get_subst_argument_mappings () const +{ + static auto empty = SubstitutionArgumentMappings::empty (); + const TyTy::BaseType *x = destructure (); + switch (x->get_kind ()) + { + case PROJECTION: { + const auto &p = *static_cast<const ProjectionType *> (x); + const auto &ref = static_cast<const SubstitutionRef &> (p); + return ref.get_substitution_arguments (); + } + break; + + case FNDEF: { + const auto &fn = *static_cast<const FnType *> (x); + const auto &ref = static_cast<const SubstitutionRef &> (fn); + return ref.get_substitution_arguments (); + } + break; + + case ADT: { + const auto &adt = *static_cast<const ADTType *> (x); + const auto &ref = static_cast<const SubstitutionRef &> (adt); + return ref.get_substitution_arguments (); + } + break; + + case CLOSURE: { + const auto &closure = *static_cast<const ClosureType *> (x); + const auto &ref = static_cast<const SubstitutionRef &> (closure); + return ref.get_substitution_arguments (); + } + break; + + default: + return empty; + } + + return empty; +} + // InferType InferType::InferType (HirId ref, InferTypeKind infer_kind, TypeHint hint, @@ -1341,9 +1486,10 @@ VariantDef::variant_type_string (VariantType type) } VariantDef::VariantDef (HirId id, DefId defid, std::string identifier, - RustIdent ident, HIR::Expr *discriminant) + RustIdent ident, + tl::optional<std::unique_ptr<HIR::Expr>> &&discriminant) : id (id), defid (defid), identifier (identifier), ident (ident), - discriminant (discriminant) + discriminant (std::move (discriminant)) { type = VariantType::NUM; @@ -1352,41 +1498,22 @@ VariantDef::VariantDef (HirId id, DefId defid, std::string identifier, VariantDef::VariantDef (HirId id, DefId defid, std::string identifier, RustIdent ident, VariantType type, - HIR::Expr *discriminant, + tl::optional<std::unique_ptr<HIR::Expr>> &&discriminant, std::vector<StructFieldType *> fields) : id (id), defid (defid), identifier (identifier), ident (ident), type (type), - discriminant (discriminant), fields (fields) + discriminant (std::move (discriminant)), fields (fields) { rust_assert ((type == VariantType::NUM && fields.empty ()) || (type == VariantType::TUPLE || type == VariantType::STRUCT)); } -VariantDef::VariantDef (const VariantDef &other) - : id (other.id), defid (other.defid), identifier (other.identifier), - ident (other.ident), type (other.type), discriminant (other.discriminant), - fields (other.fields) -{} - -VariantDef & -VariantDef::operator= (const VariantDef &other) -{ - id = other.id; - identifier = other.identifier; - type = other.type; - discriminant = other.discriminant; - fields = other.fields; - ident = other.ident; - - return *this; -} - VariantDef & VariantDef::get_error_node () { static VariantDef node = VariantDef (UNKNOWN_HIRID, UNKNOWN_DEFID, "", {Resolver::CanonicalPath::create_empty (), UNKNOWN_LOCATION}, - nullptr); + tl::nullopt); return node; } @@ -1475,18 +1602,31 @@ VariantDef::lookup_field (const std::string &lookup, return false; } -HIR::Expr * +HIR::Expr & +VariantDef::get_discriminant () +{ + return *discriminant.value (); +} + +const HIR::Expr & VariantDef::get_discriminant () const { - rust_assert (discriminant != nullptr); - return discriminant; + return *discriminant.value (); +} + +bool +VariantDef::has_discriminant () const +{ + return discriminant.has_value (); } std::string VariantDef::as_string () const { if (type == VariantType::NUM) - return identifier + " = " + discriminant->as_string (); + return identifier + + (has_discriminant () ? " = " + get_discriminant ().as_string () + : ""); std::string buffer; for (size_t i = 0; i < fields.size (); ++i) @@ -1511,9 +1651,6 @@ VariantDef::is_equal (const VariantDef &other) const if (identifier.compare (other.identifier) != 0) return false; - if (discriminant != other.discriminant) - return false; - if (fields.size () != other.fields.size ()) return false; @@ -1533,8 +1670,13 @@ VariantDef::clone () const for (auto &f : fields) cloned_fields.push_back ((StructFieldType *) f->clone ()); - return new VariantDef (id, defid, identifier, ident, type, discriminant, - cloned_fields); + auto &&discriminant_opt = has_discriminant () + ? tl::optional<std::unique_ptr<HIR::Expr>> ( + get_discriminant ().clone_expr ()) + : tl::nullopt; + + return new VariantDef (id, defid, identifier, ident, type, + std::move (discriminant_opt), cloned_fields); } VariantDef * @@ -1544,8 +1686,13 @@ VariantDef::monomorphized_clone () const for (auto &f : fields) cloned_fields.push_back ((StructFieldType *) f->monomorphized_clone ()); - return new VariantDef (id, defid, identifier, ident, type, discriminant, - cloned_fields); + auto discriminant_opt = has_discriminant () + ? tl::optional<std::unique_ptr<HIR::Expr>> ( + get_discriminant ().clone_expr ()) + : tl::nullopt; + + return new VariantDef (id, defid, identifier, ident, type, + std::move (discriminant_opt), cloned_fields); } const RustIdent & @@ -1556,6 +1703,43 @@ VariantDef::get_ident () const // ADTType +ADTType::ADTType (DefId id, HirId ref, std::string identifier, RustIdent ident, + ADTKind adt_kind, std::vector<VariantDef *> variants, + std::vector<SubstitutionParamMapping> subst_refs, + SubstitutionArgumentMappings generic_arguments, + RegionConstraints region_constraints, std::set<HirId> refs) + : BaseType (ref, ref, TypeKind::ADT, ident, refs), + SubstitutionRef (std::move (subst_refs), std::move (generic_arguments), + region_constraints), + id (id), identifier (identifier), variants (variants), adt_kind (adt_kind) +{} + +ADTType::ADTType (DefId id, HirId ref, HirId ty_ref, std::string identifier, + RustIdent ident, ADTKind adt_kind, + std::vector<VariantDef *> variants, + std::vector<SubstitutionParamMapping> subst_refs, + SubstitutionArgumentMappings generic_arguments, + RegionConstraints region_constraints, std::set<HirId> refs) + : BaseType (ref, ty_ref, TypeKind::ADT, ident, refs), + SubstitutionRef (std::move (subst_refs), std::move (generic_arguments), + region_constraints), + id (id), identifier (identifier), variants (variants), adt_kind (adt_kind) +{} + +ADTType::ADTType (DefId id, HirId ref, HirId ty_ref, std::string identifier, + RustIdent ident, ADTKind adt_kind, + std::vector<VariantDef *> variants, + std::vector<SubstitutionParamMapping> subst_refs, + ReprOptions repr, + SubstitutionArgumentMappings generic_arguments, + RegionConstraints region_constraints, std::set<HirId> refs) + : BaseType (ref, ty_ref, TypeKind::ADT, ident, refs), + SubstitutionRef (std::move (subst_refs), std::move (generic_arguments), + region_constraints), + id (id), identifier (identifier), variants (variants), adt_kind (adt_kind), + repr (repr) +{} + void ADTType::accept_vis (TyVisitor &vis) { @@ -1637,6 +1821,12 @@ ADTType::is_equal (const BaseType &other) const return true; } +DefId +ADTType::get_id () const +{ + return id; +} + BaseType * ADTType::clone () const { @@ -1644,7 +1834,7 @@ ADTType::clone () const for (auto &variant : variants) cloned_variants.push_back (variant->clone ()); - return new ADTType (get_ref (), get_ty_ref (), identifier, ident, + return new ADTType (get_id (), get_ref (), get_ty_ref (), identifier, ident, get_adt_kind (), cloned_variants, clone_substs (), get_repr_options (), used_arguments, get_region_constraints (), get_combined_refs ()); @@ -1747,9 +1937,13 @@ TupleType::TupleType (HirId ref, HirId ty_ref, location_t locus, {} TupleType * -TupleType::get_unit_type (HirId ref) +TupleType::get_unit_type () { - return new TupleType (ref, BUILTINS_LOCATION); + static TupleType *ret = nullptr; + if (ret == nullptr) + ret = new TupleType (Analysis::Mappings::get ().get_next_hir_id (), + BUILTINS_LOCATION); + return ret; } size_t @@ -1891,9 +2085,9 @@ FnType::as_string () const std::string params_str = ""; for (auto ¶m : params) { - auto pattern = param.first; - auto ty = param.second; - params_str += pattern->as_string () + " " + ty->as_string (); + auto &pattern = param.get_pattern (); + auto ty = param.get_type (); + params_str += pattern.as_string () + " " + ty->as_string (); params_str += ","; } @@ -1914,7 +2108,7 @@ FnType::is_equal (const BaseType &other) const if (get_kind () != other.get_kind ()) return false; - auto other2 = static_cast<const FnType &> (other); + auto &other2 = static_cast<const FnType &> (other); if (get_identifier ().compare (other2.get_identifier ()) != 0) return false; @@ -1948,8 +2142,8 @@ FnType::is_equal (const BaseType &other) const for (size_t i = 0; i < num_params (); i++) { - auto lhs = param_at (i).second; - auto rhs = other2.param_at (i).second; + auto lhs = param_at (i).get_type (); + auto rhs = other2.param_at (i).get_type (); if (!lhs->is_equal (*rhs)) return false; } @@ -1959,9 +2153,9 @@ FnType::is_equal (const BaseType &other) const BaseType * FnType::clone () const { - std::vector<std::pair<HIR::Pattern *, BaseType *>> cloned_params; + std::vector<TyTy::FnParam> cloned_params; for (auto &p : params) - cloned_params.push_back ({p.first, p.second->clone ()}); + cloned_params.push_back (p.clone ()); return new FnType (get_ref (), get_ty_ref (), get_id (), get_identifier (), ident, flags, abi, std::move (cloned_params), @@ -2035,7 +2229,7 @@ FnType::handle_substitions (SubstitutionArgumentMappings &subst_mappings) for (auto ¶m : fn->get_params ()) { - auto fty = param.second; + auto fty = param.get_type (); bool is_param_ty = fty->get_kind () == TypeKind::PARAM; if (is_param_ty) @@ -2054,7 +2248,7 @@ FnType::handle_substitions (SubstitutionArgumentMappings &subst_mappings) { auto new_field = argt->clone (); new_field->set_ref (fty->get_ref ()); - param.second = new_field; + param.set_type (new_field); } else { @@ -2078,7 +2272,7 @@ FnType::handle_substitions (SubstitutionArgumentMappings &subst_mappings) auto new_field = concrete->clone (); new_field->set_ref (fty->get_ref ()); - param.second = new_field; + param.set_type (new_field); } } @@ -2215,12 +2409,24 @@ void ClosureType::setup_fn_once_output () const { // lookup the lang items - auto fn_once_lang_item = LangItem::Kind::FN_ONCE; - auto fn_once_output_lang_item = LangItem::Kind::FN_ONCE_OUTPUT; + auto fn_once_lookup = mappings.lookup_lang_item (LangItem::Kind::FN_ONCE); + auto fn_once_output_lookup + = mappings.lookup_lang_item (LangItem::Kind::FN_ONCE_OUTPUT); + if (!fn_once_lookup) + { + rust_fatal_error (UNKNOWN_LOCATION, + "Missing required %<fn_once%> lang item"); + return; + } + if (!fn_once_output_lookup) + { + rust_fatal_error (UNKNOWN_LOCATION, + "Missing required %<fn_once_ouput%> lang item"); + return; + } - DefId &trait_id = mappings.lookup_lang_item (fn_once_lang_item).value (); - DefId &trait_item_id - = mappings.lookup_lang_item (fn_once_output_lang_item).value (); + DefId &trait_id = fn_once_lookup.value (); + DefId &trait_item_id = fn_once_output_lookup.value (); // resolve to the trait HIR::Item *item = mappings.lookup_defid (trait_id).value (); @@ -3350,6 +3556,140 @@ ParamType::is_implicit_self_trait () const return is_trait_self; } +// OpaqueType + +OpaqueType::OpaqueType (location_t locus, HirId ref, + std::vector<TypeBoundPredicate> specified_bounds, + std::set<HirId> refs) + : BaseType (ref, ref, KIND, + {Resolver::CanonicalPath::new_seg (UNKNOWN_NODEID, "impl"), + locus}, + specified_bounds, refs) +{} + +OpaqueType::OpaqueType (location_t locus, HirId ref, HirId ty_ref, + std::vector<TypeBoundPredicate> specified_bounds, + std::set<HirId> refs) + : BaseType (ref, ty_ref, KIND, + {Resolver::CanonicalPath::new_seg (UNKNOWN_NODEID, "impl"), + locus}, + specified_bounds, refs) +{} + +bool +OpaqueType::can_resolve () const +{ + return get_ref () != get_ty_ref (); +} + +void +OpaqueType::accept_vis (TyVisitor &vis) +{ + vis.visit (*this); +} + +void +OpaqueType::accept_vis (TyConstVisitor &vis) const +{ + vis.visit (*this); +} + +std::string +OpaqueType::as_string () const +{ + return get_name (); +} + +std::string +OpaqueType::get_name () const +{ + return "impl " + raw_bounds_as_name (); +} + +bool +OpaqueType::can_eq (const BaseType *other, bool emit_errors) const +{ + OpaqueCmp r (this, emit_errors); + return r.can_eq (other); +} + +BaseType * +OpaqueType::clone () const +{ + return new OpaqueType (ident.locus, get_ref (), get_ty_ref (), + get_specified_bounds (), get_combined_refs ()); +} + +BaseType * +OpaqueType::resolve () const +{ + TyVar var (get_ty_ref ()); + BaseType *r = var.get_tyty (); + + while (r->get_kind () == TypeKind::OPAQUE) + { + OpaqueType *rr = static_cast<OpaqueType *> (r); + if (!rr->can_resolve ()) + break; + + TyVar v (rr->get_ty_ref ()); + BaseType *n = v.get_tyty (); + + // fix infinite loop + if (r == n) + break; + + r = n; + } + + if (r->get_kind () == TypeKind::OPAQUE && (r->get_ref () == r->get_ty_ref ())) + return TyVar (r->get_ty_ref ()).get_tyty (); + + return r; +} + +bool +OpaqueType::is_equal (const BaseType &other) const +{ + auto other2 = static_cast<const OpaqueType &> (other); + if (can_resolve () != other2.can_resolve ()) + return false; + + if (can_resolve ()) + return resolve ()->can_eq (other2.resolve (), false); + + return bounds_compatible (other, UNDEF_LOCATION, false); +} + +OpaqueType * +OpaqueType::handle_substitions (SubstitutionArgumentMappings &subst_mappings) +{ + // SubstitutionArg arg = SubstitutionArg::error (); + // bool ok = subst_mappings.get_argument_for_symbol (this, &arg); + // if (!ok || arg.is_error ()) + // return this; + + // OpaqueType *p = static_cast<OpaqueType *> (clone ()); + // subst_mappings.on_param_subst (*p, arg); + + // // there are two cases one where we substitute directly to a new PARAM and + // // otherwise + // if (arg.get_tyty ()->get_kind () == TyTy::TypeKind::PARAM) + // { + // p->set_ty_ref (arg.get_tyty ()->get_ref ()); + // return p; + // } + + // // this is the new subst that this needs to pass + // p->set_ref (mappings.get_next_hir_id ()); + // p->set_ty_ref (arg.get_tyty ()->get_ref ()); + + // return p; + + rust_unreachable (); + return nullptr; +} + // StrType StrType::StrType (HirId ref, std::set<HirId> refs) @@ -3460,20 +3800,20 @@ NeverType::clone () const // placeholder type -PlaceholderType::PlaceholderType (std::string symbol, HirId ref, +PlaceholderType::PlaceholderType (std::string symbol, DefId id, HirId ref, std::set<HirId> refs) : BaseType (ref, ref, KIND, {Resolver::CanonicalPath::create_empty (), BUILTINS_LOCATION}, refs), - symbol (symbol) + symbol (symbol), defId (id) {} -PlaceholderType::PlaceholderType (std::string symbol, HirId ref, HirId ty_ref, - std::set<HirId> refs) +PlaceholderType::PlaceholderType (std::string symbol, DefId id, HirId ref, + HirId ty_ref, std::set<HirId> refs) : BaseType (ref, ty_ref, KIND, {Resolver::CanonicalPath::create_empty (), BUILTINS_LOCATION}, refs), - symbol (symbol) + symbol (symbol), defId (id) {} std::string @@ -3517,8 +3857,8 @@ PlaceholderType::can_eq (const BaseType *other, bool emit_errors) const BaseType * PlaceholderType::clone () const { - return new PlaceholderType (get_symbol (), get_ref (), get_ty_ref (), - get_combined_refs ()); + return new PlaceholderType (get_symbol (), get_def_id (), get_ref (), + get_ty_ref (), get_combined_refs ()); } void @@ -3539,7 +3879,17 @@ bool PlaceholderType::can_resolve () const { auto context = Resolver::TypeCheckContext::get (); - return context->lookup_associated_type_mapping (get_ty_ref (), nullptr); + + BaseType *lookup = nullptr; + HirId mapping; + + if (!context->lookup_associated_type_mapping (get_ty_ref (), &mapping)) + return false; + + if (!context->lookup_type (mapping, &lookup)) + return false; + + return lookup != nullptr; } BaseType * @@ -3569,6 +3919,12 @@ PlaceholderType::is_equal (const BaseType &other) const return get_symbol ().compare (other2.get_symbol ()) == 0; } +DefId +PlaceholderType::get_def_id () const +{ + return defId; +} + // Projection type ProjectionType::ProjectionType ( @@ -3792,7 +4148,7 @@ DynamicObjectType::get_object_items () const std::vector< std::pair<const Resolver::TraitItemReference *, const TypeBoundPredicate *>> items; - for (auto &bound : get_specified_bounds ()) + for (const TypeBoundPredicate &bound : get_specified_bounds ()) { const Resolver::TraitReference *trait = bound.get (); std::vector<const Resolver::TraitItemReference *> trait_items; diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h index 3975029..1cada9a 100644 --- a/gcc/rust/typecheck/rust-tyty.h +++ b/gcc/rust/typecheck/rust-tyty.h @@ -28,6 +28,7 @@ #include "rust-tyty-subst.h" #include "rust-tyty-region.h" #include "rust-system.h" +#include "rust-hir.h" namespace Rust { @@ -72,6 +73,7 @@ enum TypeKind PROJECTION, DYNAMIC, CLOSURE, + OPAQUE, // there are more to add... ERROR }; @@ -135,6 +137,9 @@ public: void inherit_bounds ( const std::vector<TyTy::TypeBoundPredicate> &specified_bounds); + // contains_infer checks if there is an inference variable inside the type + const TyTy::BaseType *contains_infer () const; + // is_unit returns whether this is just a unit-struct bool is_unit () const; @@ -173,6 +178,7 @@ public: bool has_substitutions_defined () const; bool needs_generic_substitutions () const; + const SubstitutionArgumentMappings &get_subst_argument_mappings () const; std::string mangle_string () const { @@ -406,6 +412,39 @@ private: HIR::GenericParam ¶m; }; +class OpaqueType : public BaseType +{ +public: + static constexpr auto KIND = TypeKind::OPAQUE; + + OpaqueType (location_t locus, HirId ref, + std::vector<TypeBoundPredicate> specified_bounds, + std::set<HirId> refs = std::set<HirId> ()); + + OpaqueType (location_t locus, HirId ref, HirId ty_ref, + std::vector<TypeBoundPredicate> specified_bounds, + std::set<HirId> refs = std::set<HirId> ()); + + void accept_vis (TyVisitor &vis) override; + void accept_vis (TyConstVisitor &vis) const override; + + std::string as_string () const override; + + bool can_eq (const BaseType *other, bool emit_errors) const override final; + + BaseType *clone () const final override; + + bool can_resolve () const; + + BaseType *resolve () const; + + std::string get_name () const override final; + + bool is_equal (const BaseType &other) const override; + + OpaqueType *handle_substitions (SubstitutionArgumentMappings &mappings); +}; + class StructFieldType { public: @@ -447,7 +486,7 @@ public: std::vector<TyVar> fields = std::vector<TyVar> (), std::set<HirId> refs = std::set<HirId> ()); - static TupleType *get_unit_type (HirId ref); + static TupleType *get_unit_type (); void accept_vis (TyVisitor &vis) override; void accept_vis (TyConstVisitor &vis) const override; @@ -509,6 +548,8 @@ public: void apply_generic_arguments (HIR::GenericArgs *generic_args, bool has_associated_self); + void apply_argument_mappings (SubstitutionArgumentMappings &arguments); + bool contains_item (const std::string &search) const; TypeBoundPredicateItem @@ -540,6 +581,14 @@ public: bool is_equal (const TypeBoundPredicate &other) const; + bool validate_type_implements_super_traits (TyTy::BaseType &self, + HIR::Type &impl_type, + HIR::Type &trait) const; + + bool validate_type_implements_this (TyTy::BaseType &self, + HIR::Type &impl_type, + HIR::Type &trait) const; + private: struct mark_is_error { @@ -551,6 +600,36 @@ private: location_t locus; bool error_flag; BoundPolarity polarity; + std::vector<TyTy::TypeBoundPredicate> super_traits; +}; + +class TypeBoundPredicateItem +{ +public: + TypeBoundPredicateItem (const TypeBoundPredicate parent, + const Resolver::TraitItemReference *trait_item_ref); + + TypeBoundPredicateItem (const TypeBoundPredicateItem &other); + + TypeBoundPredicateItem &operator= (const TypeBoundPredicateItem &other); + + static TypeBoundPredicateItem error (); + + bool is_error () const; + + BaseType *get_tyty_for_receiver (const TyTy::BaseType *receiver); + + const Resolver::TraitItemReference *get_raw_item () const; + + bool needs_implementation () const; + + const TypeBoundPredicate *get_parent () const; + + location_t get_locus () const; + +private: + TypeBoundPredicate parent; + const Resolver::TraitItemReference *trait_item_ref; }; // https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.VariantDef.html @@ -567,16 +646,13 @@ public: static std::string variant_type_string (VariantType type); VariantDef (HirId id, DefId defid, std::string identifier, RustIdent ident, - HIR::Expr *discriminant); + tl::optional<std::unique_ptr<HIR::Expr>> &&discriminant); VariantDef (HirId id, DefId defid, std::string identifier, RustIdent ident, - VariantType type, HIR::Expr *discriminant, + VariantType type, + tl::optional<std::unique_ptr<HIR::Expr>> &&discriminant, std::vector<StructFieldType *> fields); - VariantDef (const VariantDef &other); - - VariantDef &operator= (const VariantDef &other); - static VariantDef &get_error_node (); bool is_error () const; @@ -597,7 +673,10 @@ public: bool lookup_field (const std::string &lookup, StructFieldType **field_lookup, size_t *index) const; - HIR::Expr *get_discriminant () const; + bool has_discriminant () const; + + HIR::Expr &get_discriminant (); + const HIR::Expr &get_discriminant () const; std::string as_string () const; @@ -615,8 +694,10 @@ private: std::string identifier; RustIdent ident; VariantType type; + // can either be a structure or a discriminant value - HIR::Expr *discriminant; + tl::optional<std::unique_ptr<HIR::Expr>> discriminant; + std::vector<StructFieldType *> fields; }; @@ -633,59 +714,56 @@ public: ENUM }; + enum ReprKind + { + RUST, + C, + INT, + ALIGN, + PACKED, + // TRANSPARENT, + // SIMD, + // ... + }; + // Representation options, specified via attributes e.g. #[repr(packed)] struct ReprOptions { - // bool is_c; - // bool is_transparent; - //... + ReprKind repr_kind = ReprKind::RUST; // For align and pack: 0 = unspecified. Nonzero = byte alignment. // It is an error for both to be nonzero, this should be caught when // parsing the #[repr] attribute. unsigned char align = 0; unsigned char pack = 0; + BaseType *repr = nullptr; }; - ADTType (HirId ref, std::string identifier, RustIdent ident, ADTKind adt_kind, - std::vector<VariantDef *> variants, + ADTType (DefId id, HirId ref, std::string identifier, RustIdent ident, + ADTKind adt_kind, std::vector<VariantDef *> variants, std::vector<SubstitutionParamMapping> subst_refs, SubstitutionArgumentMappings generic_arguments = SubstitutionArgumentMappings::error (), - RegionConstraints region_constraints = {}, - std::set<HirId> refs = std::set<HirId> ()) - : BaseType (ref, ref, TypeKind::ADT, ident, refs), - SubstitutionRef (std::move (subst_refs), std::move (generic_arguments), - region_constraints), - identifier (identifier), variants (variants), adt_kind (adt_kind) - {} + RegionConstraints region_constraints = RegionConstraints{}, + std::set<HirId> refs = std::set<HirId> ()); - ADTType (HirId ref, HirId ty_ref, std::string identifier, RustIdent ident, - ADTKind adt_kind, std::vector<VariantDef *> variants, + ADTType (DefId id, HirId ref, HirId ty_ref, std::string identifier, + RustIdent ident, ADTKind adt_kind, + std::vector<VariantDef *> variants, std::vector<SubstitutionParamMapping> subst_refs, SubstitutionArgumentMappings generic_arguments = SubstitutionArgumentMappings::error (), - RegionConstraints region_constraints = {}, - std::set<HirId> refs = std::set<HirId> ()) - : BaseType (ref, ty_ref, TypeKind::ADT, ident, refs), - SubstitutionRef (std::move (subst_refs), std::move (generic_arguments), - region_constraints), - identifier (identifier), variants (variants), adt_kind (adt_kind) - {} + RegionConstraints region_constraints = RegionConstraints{}, + std::set<HirId> refs = std::set<HirId> ()); - ADTType (HirId ref, HirId ty_ref, std::string identifier, RustIdent ident, - ADTKind adt_kind, std::vector<VariantDef *> variants, + ADTType (DefId id, HirId ref, HirId ty_ref, std::string identifier, + RustIdent ident, ADTKind adt_kind, + std::vector<VariantDef *> variants, std::vector<SubstitutionParamMapping> subst_refs, ReprOptions repr, SubstitutionArgumentMappings generic_arguments = SubstitutionArgumentMappings::error (), - RegionConstraints region_constraints = {}, - std::set<HirId> refs = std::set<HirId> ()) - : BaseType (ref, ty_ref, TypeKind::ADT, ident, refs), - SubstitutionRef (std::move (subst_refs), std::move (generic_arguments), - region_constraints), - identifier (identifier), variants (variants), adt_kind (adt_kind), - repr (repr) - {} + RegionConstraints region_constraints = RegionConstraints{}, + std::set<HirId> refs = std::set<HirId> ()); ADTKind get_adt_kind () const { return adt_kind; } @@ -716,6 +794,8 @@ public: return identifier + subst_as_string (); } + DefId get_id () const; + BaseType *clone () const final override; size_t number_of_variants () const { return variants.size (); } @@ -761,12 +841,46 @@ public: handle_substitions (SubstitutionArgumentMappings &mappings) override final; private: + DefId id; std::string identifier; std::vector<VariantDef *> variants; ADTType::ADTKind adt_kind; ReprOptions repr; }; +class FnParam +{ +public: + FnParam (std::unique_ptr<HIR::Pattern> pattern, BaseType *type) + : pattern (std::move (pattern)), type (type) + {} + + FnParam (const FnParam &) = delete; + FnParam (FnParam &&) = default; + FnParam &operator= (FnParam &&) = default; + + HIR::Pattern &get_pattern () { return *pattern; } + const HIR::Pattern &get_pattern () const { return *pattern; } + + bool has_pattern () { return pattern != nullptr; } + BaseType *get_type () const { return type; } + void set_type (BaseType *new_type) { type = new_type; } + + FnParam clone () const + { + return FnParam (pattern->clone_pattern (), type->clone ()); + } + + FnParam monomorphized_clone () const + { + return FnParam (pattern->clone_pattern (), type->monomorphized_clone ()); + } + +private: + std::unique_ptr<HIR::Pattern> pattern; + BaseType *type; +}; + class FnType : public CallableTypeInterface, public SubstitutionRef { public: @@ -778,9 +892,8 @@ public: static const uint8_t FNTYPE_IS_VARADIC_FLAG = 0X04; FnType (HirId ref, DefId id, std::string identifier, RustIdent ident, - uint8_t flags, ABI abi, - std::vector<std::pair<HIR::Pattern *, BaseType *>> params, - BaseType *type, std::vector<SubstitutionParamMapping> subst_refs, + uint8_t flags, ABI abi, std::vector<FnParam> params, BaseType *type, + std::vector<SubstitutionParamMapping> subst_refs, SubstitutionArgumentMappings substitution_argument_mappings, RegionConstraints region_constraints, std::set<HirId> refs = std::set<HirId> ()) @@ -795,8 +908,7 @@ public: } FnType (HirId ref, HirId ty_ref, DefId id, std::string identifier, - RustIdent ident, uint8_t flags, ABI abi, - std::vector<std::pair<HIR::Pattern *, BaseType *>> params, + RustIdent ident, uint8_t flags, ABI abi, std::vector<FnParam> params, BaseType *type, std::vector<SubstitutionParamMapping> subst_refs, SubstitutionArgumentMappings substitution_argument_mappings, RegionConstraints region_constraints, @@ -804,13 +916,16 @@ public: : CallableTypeInterface (ref, ty_ref, TypeKind::FNDEF, ident, refs), SubstitutionRef (std::move (subst_refs), substitution_argument_mappings, region_constraints), - params (params), type (type), flags (flags), identifier (identifier), - id (id), abi (abi) + params (std::move (params)), type (type), flags (flags), + identifier (identifier), id (id), abi (abi) { LocalDefId local_def_id = id.localDefId; rust_assert (local_def_id != UNKNOWN_LOCAL_DEFID); } + FnType (const FnType &) = delete; + FnType (FnType &&) = default; + void accept_vis (TyVisitor &vis) override; void accept_vis (TyConstVisitor &vis) const override; @@ -844,28 +959,16 @@ public: BaseType *get_self_type () const { rust_assert (is_method ()); - return param_at (0).second; + return param_at (0).get_type (); } - std::vector<std::pair<HIR::Pattern *, BaseType *>> &get_params () - { - return params; - } + std::vector<FnParam> &get_params () { return params; } - const std::vector<std::pair<HIR::Pattern *, BaseType *>> &get_params () const - { - return params; - } + const std::vector<FnParam> &get_params () const { return params; } - std::pair<HIR::Pattern *, BaseType *> ¶m_at (size_t idx) - { - return params.at (idx); - } + FnParam ¶m_at (size_t idx) { return params.at (idx); } - const std::pair<HIR::Pattern *, BaseType *> ¶m_at (size_t idx) const - { - return params.at (idx); - } + const FnParam ¶m_at (size_t idx) const { return params.at (idx); } BaseType *clone () const final override; @@ -882,7 +985,7 @@ public: WARN_UNUSED_RESULT BaseType *get_param_type_at (size_t index) const override { - return param_at (index).second; + return param_at (index).get_type (); } WARN_UNUSED_RESULT BaseType *get_return_type () const override @@ -891,7 +994,7 @@ public: } private: - std::vector<std::pair<HIR::Pattern *, BaseType *>> params; + std::vector<FnParam> params; BaseType *type; uint8_t flags; std::string identifier; @@ -1505,9 +1608,9 @@ class PlaceholderType : public BaseType public: static constexpr auto KIND = TypeKind::PLACEHOLDER; - PlaceholderType (std::string symbol, HirId ref, + PlaceholderType (std::string symbol, DefId id, HirId ref, std::set<HirId> refs = std::set<HirId> ()); - PlaceholderType (std::string symbol, HirId ref, HirId ty_ref, + PlaceholderType (std::string symbol, DefId id, HirId ref, HirId ty_ref, std::set<HirId> refs = std::set<HirId> ()); void accept_vis (TyVisitor &vis) override; @@ -1533,8 +1636,11 @@ public: bool is_equal (const BaseType &other) const override; + DefId get_def_id () const; + private: std::string symbol; + DefId defId; }; class ProjectionType : public BaseType, public SubstitutionRef diff --git a/gcc/rust/typecheck/rust-unify.cc b/gcc/rust/typecheck/rust-unify.cc index fa2308f..294b677 100644 --- a/gcc/rust/typecheck/rust-unify.cc +++ b/gcc/rust/typecheck/rust-unify.cc @@ -17,7 +17,6 @@ // <http://www.gnu.org/licenses/>. #include "rust-unify.h" -#include "rust-tyty.h" namespace Rust { namespace Resolver { @@ -190,7 +189,7 @@ UnifyRules::go () == TyTy::InferType::GENERAL; bool expected_is_concrete = ltype->is_concrete () && !lhs_is_general_infer_var; - bool rneeds_infer = expected_is_concrete && rgot_param; + bool rneeds_infer = expected_is_concrete && (rgot_param); bool lgot_param = ltype->get_kind () == TyTy::TypeKind::PARAM; bool rhs_is_infer_var = rtype->get_kind () == TyTy::TypeKind::INFER; @@ -200,7 +199,7 @@ UnifyRules::go () == TyTy::InferType::GENERAL; bool receiver_is_concrete = rtype->is_concrete () && !rhs_is_general_infer_var; - bool lneeds_infer = receiver_is_concrete && lgot_param; + bool lneeds_infer = receiver_is_concrete && (lgot_param); if (rneeds_infer) { @@ -238,15 +237,6 @@ UnifyRules::go () } } - // The never type should always get coerced to the type it's being matched - // against, so in that case, ltype. This avoids doing the same check in all - // the `expect_*` functions. - // However, this does not work if we have an annoying ltype - like INFER. - // TODO: Is ltype == Infer the only special case here? What about projections? - // references? - if (rtype->get_kind () == TyTy::NEVER && ltype->get_kind () != TyTy::INFER) - return ltype->clone (); - switch (ltype->get_kind ()) { case TyTy::INFER: @@ -322,6 +312,9 @@ UnifyRules::go () case TyTy::CLOSURE: return expect_closure (static_cast<TyTy::ClosureType *> (ltype), rtype); + case TyTy::OPAQUE: + return expect_opaque (static_cast<TyTy::OpaqueType *> (ltype), rtype); + case TyTy::ERROR: return new TyTy::ErrorType (0); } @@ -410,7 +403,8 @@ UnifyRules::expect_inference_variable (TyTy::InferType *ltype, case TyTy::PLACEHOLDER: case TyTy::PROJECTION: case TyTy::DYNAMIC: - case TyTy::CLOSURE: { + case TyTy::CLOSURE: + case TyTy::OPAQUE: { bool is_valid = (ltype->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL); if (is_valid) @@ -538,6 +532,7 @@ UnifyRules::expect_adt (TyTy::ADTType *ltype, TyTy::BaseType *rtype) case TyTy::PROJECTION: case TyTy::DYNAMIC: case TyTy::CLOSURE: + case TyTy::OPAQUE: case TyTy::ERROR: return new TyTy::ErrorType (0); } @@ -582,6 +577,7 @@ UnifyRules::expect_str (TyTy::StrType *ltype, TyTy::BaseType *rtype) case TyTy::PROJECTION: case TyTy::DYNAMIC: case TyTy::CLOSURE: + case TyTy::OPAQUE: case TyTy::ERROR: return new TyTy::ErrorType (0); } @@ -652,6 +648,7 @@ UnifyRules::expect_reference (TyTy::ReferenceType *ltype, TyTy::BaseType *rtype) case TyTy::PROJECTION: case TyTy::DYNAMIC: case TyTy::CLOSURE: + case TyTy::OPAQUE: case TyTy::ERROR: return new TyTy::ErrorType (0); } @@ -722,6 +719,7 @@ UnifyRules::expect_pointer (TyTy::PointerType *ltype, TyTy::BaseType *rtype) case TyTy::PROJECTION: case TyTy::DYNAMIC: case TyTy::CLOSURE: + case TyTy::OPAQUE: case TyTy::ERROR: return new TyTy::ErrorType (0); } @@ -783,6 +781,7 @@ UnifyRules::expect_param (TyTy::ParamType *ltype, TyTy::BaseType *rtype) case TyTy::PROJECTION: case TyTy::DYNAMIC: case TyTy::CLOSURE: + case TyTy::OPAQUE: case TyTy::ERROR: return new TyTy::ErrorType (0); } @@ -842,6 +841,7 @@ UnifyRules::expect_array (TyTy::ArrayType *ltype, TyTy::BaseType *rtype) case TyTy::PROJECTION: case TyTy::DYNAMIC: case TyTy::CLOSURE: + case TyTy::OPAQUE: case TyTy::ERROR: return new TyTy::ErrorType (0); } @@ -900,6 +900,7 @@ UnifyRules::expect_slice (TyTy::SliceType *ltype, TyTy::BaseType *rtype) case TyTy::PROJECTION: case TyTy::DYNAMIC: case TyTy::CLOSURE: + case TyTy::OPAQUE: case TyTy::ERROR: return new TyTy::ErrorType (0); } @@ -929,8 +930,8 @@ UnifyRules::expect_fndef (TyTy::FnType *ltype, TyTy::BaseType *rtype) for (size_t i = 0; i < ltype->num_params (); i++) { - auto a = ltype->param_at (i).second; - auto b = type.param_at (i).second; + auto a = ltype->param_at (i).get_type (); + auto b = type.param_at (i).get_type (); auto unified_param = UnifyRules::Resolve (TyTy::TyWithLocation (a), @@ -990,6 +991,7 @@ UnifyRules::expect_fndef (TyTy::FnType *ltype, TyTy::BaseType *rtype) case TyTy::PROJECTION: case TyTy::DYNAMIC: case TyTy::CLOSURE: + case TyTy::OPAQUE: case TyTy::ERROR: return new TyTy::ErrorType (0); } @@ -1069,7 +1071,7 @@ UnifyRules::expect_fnptr (TyTy::FnPtr *ltype, TyTy::BaseType *rtype) for (size_t i = 0; i < ltype->num_params (); i++) { auto this_param = ltype->get_param_type_at (i); - auto other_param = type.param_at (i).second; + auto other_param = type.param_at (i).get_type (); auto unified_param = UnifyRules::Resolve (TyTy::TyWithLocation (this_param), @@ -1106,6 +1108,7 @@ UnifyRules::expect_fnptr (TyTy::FnPtr *ltype, TyTy::BaseType *rtype) case TyTy::PROJECTION: case TyTy::DYNAMIC: case TyTy::CLOSURE: + case TyTy::OPAQUE: case TyTy::ERROR: return new TyTy::ErrorType (0); } @@ -1176,6 +1179,7 @@ UnifyRules::expect_tuple (TyTy::TupleType *ltype, TyTy::BaseType *rtype) case TyTy::PROJECTION: case TyTy::DYNAMIC: case TyTy::CLOSURE: + case TyTy::OPAQUE: case TyTy::ERROR: return new TyTy::ErrorType (0); } @@ -1223,6 +1227,7 @@ UnifyRules::expect_bool (TyTy::BoolType *ltype, TyTy::BaseType *rtype) case TyTy::PROJECTION: case TyTy::DYNAMIC: case TyTy::CLOSURE: + case TyTy::OPAQUE: case TyTy::ERROR: return new TyTy::ErrorType (0); } @@ -1270,6 +1275,7 @@ UnifyRules::expect_char (TyTy::CharType *ltype, TyTy::BaseType *rtype) case TyTy::PROJECTION: case TyTy::DYNAMIC: case TyTy::CLOSURE: + case TyTy::OPAQUE: case TyTy::ERROR: return new TyTy::ErrorType (0); } @@ -1324,6 +1330,7 @@ UnifyRules::expect_int (TyTy::IntType *ltype, TyTy::BaseType *rtype) case TyTy::PROJECTION: case TyTy::DYNAMIC: case TyTy::CLOSURE: + case TyTy::OPAQUE: case TyTy::ERROR: return new TyTy::ErrorType (0); } @@ -1378,6 +1385,7 @@ UnifyRules::expect_uint (TyTy::UintType *ltype, TyTy::BaseType *rtype) case TyTy::PROJECTION: case TyTy::DYNAMIC: case TyTy::CLOSURE: + case TyTy::OPAQUE: case TyTy::ERROR: return new TyTy::ErrorType (0); } @@ -1432,6 +1440,7 @@ UnifyRules::expect_float (TyTy::FloatType *ltype, TyTy::BaseType *rtype) case TyTy::PROJECTION: case TyTy::DYNAMIC: case TyTy::CLOSURE: + case TyTy::OPAQUE: case TyTy::ERROR: return new TyTy::ErrorType (0); } @@ -1479,6 +1488,7 @@ UnifyRules::expect_isize (TyTy::ISizeType *ltype, TyTy::BaseType *rtype) case TyTy::PROJECTION: case TyTy::DYNAMIC: case TyTy::CLOSURE: + case TyTy::OPAQUE: case TyTy::ERROR: return new TyTy::ErrorType (0); } @@ -1526,6 +1536,7 @@ UnifyRules::expect_usize (TyTy::USizeType *ltype, TyTy::BaseType *rtype) case TyTy::PROJECTION: case TyTy::DYNAMIC: case TyTy::CLOSURE: + case TyTy::OPAQUE: case TyTy::ERROR: return new TyTy::ErrorType (0); } @@ -1591,6 +1602,7 @@ UnifyRules::expect_placeholder (TyTy::PlaceholderType *ltype, case TyTy::USIZE: case TyTy::ISIZE: case TyTy::NEVER: + case TyTy::OPAQUE: if (infer_flag) return rtype->clone (); gcc_fallthrough (); @@ -1642,6 +1654,7 @@ UnifyRules::expect_projection (TyTy::ProjectionType *ltype, case TyTy::ISIZE: case TyTy::NEVER: case TyTy::PLACEHOLDER: + case TyTy::OPAQUE: case TyTy::ERROR: return new TyTy::ErrorType (0); } @@ -1700,6 +1713,7 @@ UnifyRules::expect_dyn (TyTy::DynamicObjectType *ltype, TyTy::BaseType *rtype) case TyTy::NEVER: case TyTy::PLACEHOLDER: case TyTy::PROJECTION: + case TyTy::OPAQUE: case TyTy::ERROR: return new TyTy::ErrorType (0); } @@ -1770,6 +1784,65 @@ UnifyRules::expect_closure (TyTy::ClosureType *ltype, TyTy::BaseType *rtype) case TyTy::PLACEHOLDER: case TyTy::PROJECTION: case TyTy::DYNAMIC: + case TyTy::OPAQUE: + case TyTy::ERROR: + return new TyTy::ErrorType (0); + } + return new TyTy::ErrorType (0); +} + +TyTy::BaseType * +UnifyRules::expect_opaque (TyTy::OpaqueType *ltype, TyTy::BaseType *rtype) +{ + switch (rtype->get_kind ()) + { + case TyTy::INFER: { + TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype); + bool is_valid + = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; + if (is_valid) + return ltype->clone (); + } + break; + + case TyTy::OPAQUE: { + auto &type = *static_cast<TyTy::OpaqueType *> (rtype); + if (ltype->num_specified_bounds () != type.num_specified_bounds ()) + { + return new TyTy::ErrorType (0); + } + + if (!ltype->bounds_compatible (type, locus, true)) + { + return new TyTy::ErrorType (0); + } + + return ltype->clone (); + } + break; + + case TyTy::CLOSURE: + case TyTy::SLICE: + case TyTy::PARAM: + case TyTy::POINTER: + case TyTy::STR: + case TyTy::ADT: + case TyTy::REF: + case TyTy::ARRAY: + case TyTy::FNDEF: + case TyTy::FNPTR: + case TyTy::TUPLE: + case TyTy::BOOL: + case TyTy::CHAR: + case TyTy::INT: + case TyTy::UINT: + case TyTy::FLOAT: + case TyTy::USIZE: + case TyTy::ISIZE: + case TyTy::NEVER: + case TyTy::PLACEHOLDER: + case TyTy::PROJECTION: + case TyTy::DYNAMIC: case TyTy::ERROR: return new TyTy::ErrorType (0); } diff --git a/gcc/rust/typecheck/rust-unify.h b/gcc/rust/typecheck/rust-unify.h index 20f7b4e..5ff3b7c 100644 --- a/gcc/rust/typecheck/rust-unify.h +++ b/gcc/rust/typecheck/rust-unify.h @@ -82,6 +82,8 @@ protected: TyTy::BaseType *rtype); TyTy::BaseType *expect_closure (TyTy::ClosureType *ltype, TyTy::BaseType *rtype); + TyTy::BaseType *expect_opaque (TyTy::OpaqueType *ltype, + TyTy::BaseType *rtype); private: UnifyRules (TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs, diff --git a/gcc/rust/util/expected.h b/gcc/rust/util/expected.h index a9e3bc2..07ba877 100644 --- a/gcc/rust/util/expected.h +++ b/gcc/rust/util/expected.h @@ -212,10 +212,8 @@ template <typename E> throw std::forward<E>(e); #else (void)e; -#ifdef _MSC_VER gcc_unreachable(); #endif -#endif } #ifndef TL_TRAITS_MUTEX @@ -2437,4 +2435,4 @@ void swap(expected<T, E> &lhs, } } // namespace tl -#endif
\ No newline at end of file +#endif diff --git a/gcc/rust/util/optional.h b/gcc/rust/util/optional.h index b2011b7..2c59459 100644 --- a/gcc/rust/util/optional.h +++ b/gcc/rust/util/optional.h @@ -1249,19 +1249,56 @@ public: /// Returns a pointer to the stored value constexpr const T *operator->() const { + // constexpr function must only contain a return statement in C++11 +#ifdef TL_OPTIONAL_CXX14 + // undefined behavior if we don't have a value + rust_assert(has_value ()); +#endif + return std::addressof(this->m_value); } TL_OPTIONAL_11_CONSTEXPR T *operator->() { + // constexpr function must only contain a return statement in C++11 +#ifdef TL_OPTIONAL_CXX14 + // undefined behavior if we don't have a value + rust_assert(has_value ()); +#endif + return std::addressof(this->m_value); } /// Returns the stored value - TL_OPTIONAL_11_CONSTEXPR T &operator*() & { return this->m_value; } + TL_OPTIONAL_11_CONSTEXPR T &operator*() & + { + // constexpr function must only contain a return statement in C++11 +#ifdef TL_OPTIONAL_CXX14 + // undefined behavior if we don't have a value + rust_assert(has_value ()); +#endif - constexpr const T &operator*() const & { return this->m_value; } + return this->m_value; + } + + constexpr const T &operator*() const & + { + // constexpr function must only contain a return statement in C++11 +#ifdef TL_OPTIONAL_CXX14 + // undefined behavior if we don't have a value + rust_assert(has_value ()); +#endif + + return this->m_value; + } + + TL_OPTIONAL_11_CONSTEXPR T &&operator*() && + { + // constexpr function must only contain a return statement in C++11 +#ifdef TL_OPTIONAL_CXX14 + // undefined behavior if we don't have a value + rust_assert(has_value ()); +#endif - TL_OPTIONAL_11_CONSTEXPR T &&operator*() && { return std::move(this->m_value); } @@ -1988,14 +2025,49 @@ public: void swap(optional &rhs) noexcept { std::swap(m_value, rhs.m_value); } /// Returns a pointer to the stored value - constexpr const T *operator->() const noexcept { return m_value; } + constexpr const T *operator->() const noexcept + { + // constexpr function must only contain a return statement in C++11 +#ifdef TL_OPTIONAL_CXX14 + // undefined behavior if we don't have a value + rust_assert(has_value ()); +#endif + + return m_value; + } - TL_OPTIONAL_11_CONSTEXPR T *operator->() noexcept { return m_value; } + TL_OPTIONAL_11_CONSTEXPR T *operator->() noexcept + { + // constexpr function must only contain a return statement in C++11 +#ifdef TL_OPTIONAL_CXX14 + // undefined behavior if we don't have a value + rust_assert(has_value ()); +#endif + + return m_value; + } /// Returns the stored value - TL_OPTIONAL_11_CONSTEXPR T &operator*() noexcept { return *m_value; } + TL_OPTIONAL_11_CONSTEXPR T &operator*() noexcept { + // constexpr function must only contain a return statement in C++11 +#ifdef TL_OPTIONAL_CXX14 + // undefined behavior if we don't have a value + rust_assert(has_value ()); +#endif + + return *m_value; + } - constexpr const T &operator*() const noexcept { return *m_value; } + constexpr const T &operator*() const noexcept + { + // constexpr function must only contain a return statement in C++11 +#ifdef TL_OPTIONAL_CXX14 + // undefined behavior if we don't have a value + rust_assert(has_value ()); +#endif + + return *m_value; + } constexpr bool has_value() const noexcept { return m_value != nullptr; } diff --git a/gcc/rust/util/rust-attribute-values.h b/gcc/rust/util/rust-attribute-values.h index 9041701..47e6a17 100644 --- a/gcc/rust/util/rust-attribute-values.h +++ b/gcc/rust/util/rust-attribute-values.h @@ -29,6 +29,7 @@ public: static constexpr auto &COLD = "cold"; static constexpr auto &CFG = "cfg"; static constexpr auto &CFG_ATTR = "cfg_attr"; + static constexpr auto &DERIVE_ATTR = "derive"; static constexpr auto &DEPRECATED = "deprecated"; static constexpr auto &ALLOW = "allow"; static constexpr auto &ALLOW_INTERNAL_UNSTABLE = "allow_internal_unstable"; @@ -39,12 +40,14 @@ public: static constexpr auto &NO_MANGLE = "no_mangle"; static constexpr auto &REPR = "repr"; static constexpr auto &RUSTC_BUILTIN_MACRO = "rustc_builtin_macro"; + static constexpr auto &RUSTC_MACRO_TRANSPARENCY = "rustc_macro_transparency"; static constexpr auto &PATH = "path"; static constexpr auto &MACRO_USE = "macro_use"; static constexpr auto &MACRO_EXPORT = "macro_export"; static constexpr auto &PROC_MACRO = "proc_macro"; static constexpr auto &PROC_MACRO_DERIVE = "proc_macro_derive"; static constexpr auto &PROC_MACRO_ATTRIBUTE = "proc_macro_attribute"; + static constexpr auto &TARGET_FEATURE = "target_feature"; // From now on, these are reserved by the compiler and gated through // #![feature(rustc_attrs)] @@ -53,9 +56,35 @@ public: = "rustc_inherit_overflow_checks"; static constexpr auto &STABLE = "stable"; static constexpr auto &UNSTABLE = "unstable"; + + static constexpr auto &RUSTC_PROMOTABLE = "rustc_promotable"; static constexpr auto &RUSTC_CONST_STABLE = "rustc_const_stable"; static constexpr auto &RUSTC_CONST_UNSTABLE = "rustc_const_unstable"; + + static constexpr auto &RUSTC_SPECIALIZATION_TRAIT + = "rustc_specialization_trait"; + static constexpr auto &RUSTC_UNSAFE_SPECIALIZATION_MARKER + = "rustc_unsafe_specialization_marker"; + static constexpr auto &RUSTC_RESERVATION_IMPL = "rustc_reservation_impl"; + static constexpr auto &RUSTC_PAREN_SUGAR = "rustc_paren_sugar"; + static constexpr auto &RUSTC_NONNULL_OPTIMIZATION_GUARANTEED + = "rustc_nonnull_optimization_guaranteed"; + + static constexpr auto &RUSTC_LAYOUT_SCALAR_VALID_RANGE_START + = "rustc_layout_scalar_valid_range_start"; + static constexpr auto &MAY_DANGLE = "may_dangle"; + static constexpr auto &PRELUDE_IMPORT = "prelude_import"; + static constexpr auto &TRACK_CALLER = "track_caller"; + + static constexpr auto &RUSTC_DIAGNOSTIC_ITEM = "rustc_diagnostic_item"; + static constexpr auto &RUSTC_ON_UNIMPLEMENTED = "rustc_on_unimplemented"; + + static constexpr auto &FUNDAMENTAL = "fundamental"; + + static constexpr auto &NON_EXHAUSTIVE = "non_exhaustive"; + + static constexpr auto &RUSTFMT = "rustfmt"; }; } // namespace Values } // namespace Rust diff --git a/gcc/rust/util/rust-attributes.cc b/gcc/rust/util/rust-attributes.cc index c9e3764..c77e99c 100644 --- a/gcc/rust/util/rust-attributes.cc +++ b/gcc/rust/util/rust-attributes.cc @@ -29,6 +29,15 @@ namespace Rust { namespace Analysis { +bool +Attributes::is_known (const std::string &attribute_path) +{ + const auto &lookup + = BuiltinAttributeMappings::get ()->lookup_builtin (attribute_path); + + return !lookup.is_error (); +} + using Attrs = Values::Attributes; // https://doc.rust-lang.org/stable/nightly-rustc/src/rustc_feature/builtin_attrs.rs.html#248 @@ -37,6 +46,7 @@ static const BuiltinAttrDefinition __definitions[] {Attrs::COLD, CODE_GENERATION}, {Attrs::CFG, EXPANSION}, {Attrs::CFG_ATTR, EXPANSION}, + {Attrs::DERIVE_ATTR, EXPANSION}, {Attrs::DEPRECATED, STATIC_ANALYSIS}, {Attrs::ALLOW, STATIC_ANALYSIS}, {Attrs::ALLOW_INTERNAL_UNSTABLE, STATIC_ANALYSIS}, @@ -47,6 +57,7 @@ static const BuiltinAttrDefinition __definitions[] {Attrs::NO_MANGLE, CODE_GENERATION}, {Attrs::REPR, CODE_GENERATION}, {Attrs::RUSTC_BUILTIN_MACRO, EXPANSION}, + {Attrs::RUSTC_MACRO_TRANSPARENCY, EXPANSION}, {Attrs::PATH, EXPANSION}, {Attrs::MACRO_USE, NAME_RESOLUTION}, {Attrs::MACRO_EXPORT, NAME_RESOLUTION}, @@ -62,9 +73,29 @@ static const BuiltinAttrDefinition __definitions[] {Attrs::RUSTC_INHERIT_OVERFLOW_CHECKS, CODE_GENERATION}, {Attrs::STABLE, STATIC_ANALYSIS}, {Attrs::UNSTABLE, STATIC_ANALYSIS}, + // assuming we keep these for static analysis + {Attrs::RUSTC_PROMOTABLE, CODE_GENERATION}, {Attrs::RUSTC_CONST_STABLE, STATIC_ANALYSIS}, - {Attrs::RUSTC_CONST_UNSTABLE, STATIC_ANALYSIS}}; + {Attrs::RUSTC_CONST_UNSTABLE, STATIC_ANALYSIS}, + {Attrs::PRELUDE_IMPORT, NAME_RESOLUTION}, + {Attrs::TRACK_CALLER, CODE_GENERATION}, + {Attrs::RUSTC_SPECIALIZATION_TRAIT, TYPE_CHECK}, + {Attrs::RUSTC_UNSAFE_SPECIALIZATION_MARKER, TYPE_CHECK}, + {Attrs::RUSTC_RESERVATION_IMPL, TYPE_CHECK}, + {Attrs::RUSTC_PAREN_SUGAR, TYPE_CHECK}, + {Attrs::RUSTC_NONNULL_OPTIMIZATION_GUARANTEED, TYPE_CHECK}, + + {Attrs::RUSTC_LAYOUT_SCALAR_VALID_RANGE_START, CODE_GENERATION}, + + {Attrs::PRELUDE_IMPORT, NAME_RESOLUTION}, + + {Attrs::RUSTC_DIAGNOSTIC_ITEM, STATIC_ANALYSIS}, + {Attrs::RUSTC_ON_UNIMPLEMENTED, STATIC_ANALYSIS}, + + {Attrs::FUNDAMENTAL, TYPE_CHECK}, + {Attrs::NON_EXHAUSTIVE, TYPE_CHECK}, + {Attrs::RUSTFMT, EXTERNAL}}; BuiltinAttributeMappings * BuiltinAttributeMappings::get () diff --git a/gcc/rust/util/rust-attributes.h b/gcc/rust/util/rust-attributes.h index 1345168..7c7a1fc 100644 --- a/gcc/rust/util/rust-attributes.h +++ b/gcc/rust/util/rust-attributes.h @@ -25,6 +25,12 @@ namespace Rust { namespace Analysis { +class Attributes +{ +public: + static bool is_known (const std::string &attribute_path); +}; + enum CompilerPass { UNKNOWN, @@ -34,7 +40,12 @@ enum CompilerPass HIR_LOWERING, TYPE_CHECK, STATIC_ANALYSIS, - CODE_GENERATION + CODE_GENERATION, + + // External Rust tooling attributes, like #[rustfmt::skip] + EXTERNAL, + + // Do we need to add something here for const fns? }; struct BuiltinAttrDefinition diff --git a/gcc/rust/util/rust-canonical-path.h b/gcc/rust/util/rust-canonical-path.h index af151c2..4d8f954 100644 --- a/gcc/rust/util/rust-canonical-path.h +++ b/gcc/rust/util/rust-canonical-path.h @@ -46,7 +46,9 @@ namespace Resolver { class CanonicalPath { public: - CanonicalPath (const CanonicalPath &other) : segs (other.segs) {} + CanonicalPath (const CanonicalPath &other) + : segs (other.segs), crate_num (other.crate_num) + {} CanonicalPath &operator= (const CanonicalPath &other) { diff --git a/gcc/rust/util/rust-common.h b/gcc/rust/util/rust-common.h index 2033694..71637ce 100644 --- a/gcc/rust/util/rust-common.h +++ b/gcc/rust/util/rust-common.h @@ -21,7 +21,6 @@ #ifndef RUST_COMMON #define RUST_COMMON #include "rust-system.h" -#include <string> namespace Rust { diff --git a/gcc/rust/util/rust-edition.cc b/gcc/rust/util/rust-edition.cc new file mode 100644 index 0000000..4e44a91 --- /dev/null +++ b/gcc/rust/util/rust-edition.cc @@ -0,0 +1,40 @@ +// Copyright (C) 2025 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-edition.h" +#include "rust-session-manager.h" + +namespace Rust { + +Edition +get_rust_edition () +{ + switch (Session::get_instance ().options.get_edition ()) + { + case CompileOptions::Edition::E2015: + return Edition::E2015; + case CompileOptions::Edition::E2018: + return Edition::E2018; + case CompileOptions::Edition::E2021: + return Edition::E2021; + default: + rust_unreachable (); + } +} + +} // namespace Rust diff --git a/gcc/rust/util/rust-edition.h b/gcc/rust/util/rust-edition.h new file mode 100644 index 0000000..d034ea0 --- /dev/null +++ b/gcc/rust/util/rust-edition.h @@ -0,0 +1,41 @@ +// Copyright (C) 2025 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_EDITION_H +#define RUST_EDITION_H + +/* + * This header exists to avoid including rust-session-manager.h + * when we only need information on the selected rust edition + */ + +namespace Rust { + +enum class Edition +{ + E2015, + E2018, + E2021 +}; + +Edition +get_rust_edition (); + +} // namespace Rust + +#endif // !RUST_EDITION_H diff --git a/gcc/rust/util/rust-hir-map.cc b/gcc/rust/util/rust-hir-map.cc index 03b3343..eaa640c 100644 --- a/gcc/rust/util/rust-hir-map.cc +++ b/gcc/rust/util/rust-hir-map.cc @@ -148,6 +148,16 @@ Mappings::get_crate_name (CrateNum crate_num) const return it->second; } +tl::optional<CrateNum> +Mappings::lookup_crate_num (NodeId node_id) const +{ + auto it = crate_node_to_crate_num.find (node_id); + if (it == crate_node_to_crate_num.end ()) + return tl::nullopt; + + return it->second; +} + void Mappings::set_crate_name (CrateNum crate_num, const std::string &name) { @@ -184,13 +194,7 @@ Mappings::crate_num_to_nodeid (const CrateNum &crate_num) const bool Mappings::node_is_crate (NodeId node_id) const { - for (const auto &it : ast_crate_mappings) - { - NodeId crate_node_id = it.second->get_node_id (); - if (crate_node_id == node_id) - return true; - } - return false; + return lookup_crate_num (node_id).has_value (); } NodeId @@ -262,6 +266,7 @@ Mappings::insert_ast_crate (std::unique_ptr<AST::Crate> &&crate, rust_assert (it == ast_crate_mappings.end ()); // store it + crate_node_to_crate_num.insert ({crate->get_node_id (), crate_num}); ast_crate_mappings.insert ({crate_num, crate.release ()}); // return the reference to it @@ -459,7 +464,7 @@ Mappings::insert_hir_impl_block (HIR::ImplBlock *item) auto id = item->get_mappings ().get_hirid (); rust_assert (!lookup_hir_impl_block (id)); - HirId impl_type_id = item->get_type ()->get_mappings ().get_hirid (); + HirId impl_type_id = item->get_type ().get_mappings ().get_hirid (); hirImplBlockMappings[id] = item; hirImplBlockTypeMappings[impl_type_id] = item; insert_node_to_hir (item->get_mappings ().get_nodeid (), id); @@ -874,7 +879,7 @@ Mappings::insert_macro_def (AST::MacroRulesDefinition *macro) auto it = macroMappings.find (macro->get_node_id ()); rust_assert (it == macroMappings.end ()); - macroMappings[macro->get_node_id ()] = macro; + macroMappings[macro->get_node_id ()] = {macro, currentCrateNum}; } tl::optional<AST::MacroRulesDefinition *> @@ -884,7 +889,17 @@ Mappings::lookup_macro_def (NodeId id) if (it == macroMappings.end ()) return tl::nullopt; - return it->second; + return it->second.first; +} + +tl::optional<CrateNum> +Mappings::lookup_macro_def_crate (NodeId id) +{ + auto it = macroMappings.find (id); + if (it == macroMappings.end ()) + return tl::nullopt; + + return it->second.second; } void @@ -1241,6 +1256,9 @@ Mappings::lookup_builtin_marker () return builtinMarker; } +// FIXME: Before merging: Should we remove the `locus` parameter here? since +// lang items are looked up mostly for code generation, it doesn't make sense to +// error out on the locus of the node trying to access an inexistant lang item DefId Mappings::get_lang_item (LangItem::Kind item_type, location_t locus) { @@ -1258,5 +1276,85 @@ Mappings::lookup_trait_item_lang_item (LangItem::Kind item, location_t locus) return lookup_trait_item_defid (trait_item_id); } +void +Mappings::insert_lang_item (LangItem::Kind item_type, DefId id) +{ + auto it = lang_item_mappings.find (item_type); + rust_assert (it == lang_item_mappings.end ()); + + lang_item_mappings[item_type] = id; +} + +tl::optional<DefId &> +Mappings::lookup_lang_item (LangItem::Kind item_type) +{ + auto it = lang_item_mappings.find (item_type); + if (it == lang_item_mappings.end ()) + return tl::nullopt; + + return it->second; +} + +void +Mappings::insert_lang_item_node (LangItem::Kind item_type, NodeId node_id) +{ + auto it = lang_item_nodes.find (item_type); + rust_assert (it == lang_item_nodes.end ()); + + lang_item_nodes.insert ({item_type, node_id}); +} + +tl::optional<NodeId &> +Mappings::lookup_lang_item_node (LangItem::Kind item_type) +{ + auto it = lang_item_nodes.find (item_type); + if (it == lang_item_nodes.end ()) + return tl::nullopt; + + return it->second; +} + +NodeId +Mappings::get_lang_item_node (LangItem::Kind item_type) +{ + if (auto lookup = lookup_lang_item_node (item_type)) + return *lookup; + + rust_fatal_error (UNKNOWN_LOCATION, "undeclared lang item: %qs", + LangItem::PrettyString (item_type).c_str ()); +} + +void +Mappings::insert_auto_trait (HIR::Trait *trait) +{ + auto_traits.emplace_back (trait); +} + +std::vector<HIR::Trait *> & +Mappings::get_auto_traits () +{ + return auto_traits; +} + +void +Mappings::add_capture (NodeId closure, NodeId definition) +{ + auto cap = captures.find (closure); + if (cap == captures.end ()) + captures[closure] = {definition}; + else + cap->second.push_back (definition); +} + +tl::optional<std::vector<NodeId>> +Mappings::lookup_captures (NodeId closure) +{ + auto cap = captures.find (closure); + if (cap == captures.end ()) + return tl::nullopt; + else + return cap->second; +} + } // namespace Analysis } // namespace Rust diff --git a/gcc/rust/util/rust-hir-map.h b/gcc/rust/util/rust-hir-map.h index bb7318e..b523a36 100644 --- a/gcc/rust/util/rust-hir-map.h +++ b/gcc/rust/util/rust-hir-map.h @@ -81,6 +81,8 @@ public: void set_current_crate (CrateNum crateNum); CrateNum get_current_crate () const; tl::optional<const std::string &> get_crate_name (CrateNum crate_num) const; + + tl::optional<CrateNum> lookup_crate_num (NodeId node_id) const; void set_crate_name (CrateNum crate_num, const std::string &name); const std::string &get_current_crate_name () const; tl::optional<CrateNum> @@ -256,22 +258,12 @@ public: return it->second; } - void insert_lang_item (LangItem::Kind item_type, DefId id) - { - auto it = lang_item_mappings.find (item_type); - rust_assert (it == lang_item_mappings.end ()); - - lang_item_mappings[item_type] = id; - } - - tl::optional<DefId &> lookup_lang_item (LangItem::Kind item_type) - { - auto it = lang_item_mappings.find (item_type); - if (it == lang_item_mappings.end ()) - return tl::nullopt; + void insert_lang_item (LangItem::Kind item_type, DefId id); + tl::optional<DefId &> lookup_lang_item (LangItem::Kind item_type); - return it->second; - } + void insert_lang_item_node (LangItem::Kind item_type, NodeId node_id); + tl::optional<NodeId &> lookup_lang_item_node (LangItem::Kind item_type); + NodeId get_lang_item_node (LangItem::Kind item_type); // This will fatal_error when this lang item does not exist DefId get_lang_item (LangItem::Kind item_type, location_t locus); @@ -279,6 +271,7 @@ public: void insert_macro_def (AST::MacroRulesDefinition *macro); tl::optional<AST::MacroRulesDefinition *> lookup_macro_def (NodeId id); + tl::optional<CrateNum> lookup_macro_def_crate (NodeId id); void insert_macro_invocation (AST::MacroInvocation &invoc, AST::MacroRulesDefinition *def); @@ -352,6 +345,11 @@ public: tl::optional<HIR::TraitItem *> lookup_trait_item_lang_item (LangItem::Kind item, location_t locus); + void insert_auto_trait (HIR::Trait *trait); + std::vector<HIR::Trait *> &get_auto_traits (); + void add_capture (NodeId closure, NodeId definition); + tl::optional<std::vector<NodeId>> lookup_captures (NodeId closure); + private: Mappings (); @@ -389,7 +387,15 @@ private: std::map<HirId, HIR::GenericParam *> hirGenericParamMappings; std::map<HirId, HIR::Trait *> hirTraitItemsToTraitMappings; std::map<HirId, HIR::Pattern *> hirPatternMappings; + + // FIXME: Add documentation + std::vector<HIR::Trait *> auto_traits; + + // We need to have two maps here, as lang-items need to be used for both AST + // passes and HIR passes. Thus those two maps are created at different times. std::map<LangItem::Kind, DefId> lang_item_mappings; + std::map<LangItem::Kind, NodeId> lang_item_nodes; + std::map<NodeId, Resolver::CanonicalPath> paths; std::map<NodeId, location_t> locations; std::map<NodeId, HirId> nodeIdToHirMappings; @@ -399,7 +405,8 @@ private: std::map<CrateNum, std::set<HirId>> hirNodesWithinCrate; // MBE macros - std::map<NodeId, AST::MacroRulesDefinition *> macroMappings; + std::map<NodeId, std::pair<AST::MacroRulesDefinition *, CrateNum>> + macroMappings; std::map<NodeId, AST::MacroRulesDefinition *> macroInvocations; std::vector<NodeId> exportedMacros; @@ -433,6 +440,9 @@ private: // AST mappings std::map<NodeId, AST::Item *> ast_item_mappings; + + // Closure AST NodeId -> vector of Definition node ids + std::unordered_map<NodeId, std::vector<NodeId>> captures; }; } // namespace Analysis diff --git a/gcc/rust/util/rust-lang-item.cc b/gcc/rust/util/rust-lang-item.cc index 5ddffaa..9aff31b 100644 --- a/gcc/rust/util/rust-lang-item.cc +++ b/gcc/rust/util/rust-lang-item.cc @@ -46,6 +46,7 @@ const BiMap<std::string, LangItem::Kind> Rust::LangItem::lang_items = {{ {"shr_assign", Kind::SHR_ASSIGN}, {"deref", Kind::DEREF}, {"deref_mut", Kind::DEREF_MUT}, + {"receiver", Kind::RECEIVER}, {"index", Kind::INDEX}, {"index_mut", Kind::INDEX_MUT}, {"RangeFull", Kind::RANGE_FULL}, @@ -62,6 +63,7 @@ const BiMap<std::string, LangItem::Kind> Rust::LangItem::lang_items = {{ {"copy", Kind::COPY}, {"clone", Kind::CLONE}, {"sized", Kind::SIZED}, + {"sync", Kind::SYNC}, {"slice_alloc", Kind::SLICE_ALLOC}, {"slice_u8_alloc", Kind::SLICE_U8_ALLOC}, {"str_alloc", Kind::STR_ALLOC}, @@ -91,6 +93,32 @@ const BiMap<std::string, LangItem::Kind> Rust::LangItem::lang_items = {{ {"str", Kind::STR}, {"f32_runtime", Kind::F32_RUNTIME}, {"f64_runtime", Kind::F64_RUNTIME}, + + {"Some", Kind::OPTION_SOME}, + {"None", Kind::OPTION_NONE}, + + {"Ok", Kind::RESULT_OK}, + {"Err", Kind::RESULT_ERR}, + + {"into_iter", Kind::INTOITER_INTOITER}, + {"next", Kind::ITERATOR_NEXT}, + + {"eq", Kind::EQ}, + {"partial_ord", Kind::PARTIAL_ORD}, + + {"try", Kind::TRY}, + {"into_result", Kind::TRY_INTO_RESULT}, + {"from_error", Kind::TRY_FROM_ERROR}, + {"from_ok", Kind::TRY_FROM_OK}, + + {"from", Kind::FROM_FROM}, + + {"structural_peq", Kind::STRUCTURAL_PEQ}, + {"structural_teq", Kind::STRUCTURAL_TEQ}, + + {"discriminant_kind", Kind::DISCRIMINANT_KIND}, + {"discriminant_type", Kind::DISCRIMINANT_TYPE}, + {"manually_drop", Kind::MANUALLY_DROP}, }}; tl::optional<LangItem::Kind> @@ -108,6 +136,12 @@ LangItem::ToString (LangItem::Kind type) return str.value (); } +std::string +LangItem::PrettyString (LangItem::Kind type) +{ + return "#[lang = \"" + LangItem::ToString (type) + "\"]"; +} + LangItem::Kind LangItem::OperatorToLangItem (ArithmeticOrLogicalOperator op) { @@ -139,6 +173,47 @@ LangItem::OperatorToLangItem (ArithmeticOrLogicalOperator op) } LangItem::Kind +LangItem::ComparisonToLangItem (ComparisonOperator op) +{ + switch (op) + { + case ComparisonOperator::NOT_EQUAL: + case ComparisonOperator::EQUAL: + return LangItem::Kind::EQ; + + case ComparisonOperator::GREATER_THAN: + case ComparisonOperator::LESS_THAN: + case ComparisonOperator::GREATER_OR_EQUAL: + case ComparisonOperator::LESS_OR_EQUAL: + return LangItem::Kind::PARTIAL_ORD; + } + + rust_unreachable (); +} + +std::string +LangItem::ComparisonToSegment (ComparisonOperator op) +{ + switch (op) + { + case ComparisonOperator::NOT_EQUAL: + return "ne"; + case ComparisonOperator::EQUAL: + return "eq"; + case ComparisonOperator::GREATER_THAN: + return "gt"; + case ComparisonOperator::LESS_THAN: + return "lt"; + case ComparisonOperator::GREATER_OR_EQUAL: + return "ge"; + case ComparisonOperator::LESS_OR_EQUAL: + return "le"; + } + + rust_unreachable (); +} + +LangItem::Kind LangItem::CompoundAssignmentOperatorToLangItem (ArithmeticOrLogicalOperator op) { switch (op) @@ -182,4 +257,13 @@ LangItem::NegationOperatorToLangItem (NegationOperator op) rust_unreachable (); } +bool +LangItem::IsEnumVariant (LangItem::Kind type) +{ + const static std::set<LangItem::Kind> enum_variants + = {Kind::OPTION_NONE, Kind::OPTION_SOME, Kind::RESULT_OK, Kind::RESULT_ERR}; + + return enum_variants.find (type) != enum_variants.end (); +} + } // namespace Rust diff --git a/gcc/rust/util/rust-lang-item.h b/gcc/rust/util/rust-lang-item.h index 951e4a3..67a5d9c 100644 --- a/gcc/rust/util/rust-lang-item.h +++ b/gcc/rust/util/rust-lang-item.h @@ -23,12 +23,15 @@ namespace Rust { -// https://github.com/rust-lang/rust/blob/master/library/core/src/ops/arith.rs class LangItem { public: + // FIXME: We should clean up that enum to make it more inline with the list of + // lang-items in Rust 1.49 + // https://github.com/rust-lang/rust/blob/1.49.0/compiler/rustc_hir/src/lang_items.rs enum class Kind { + // https://github.com/rust-lang/rust/blob/master/library/core/src/ops/arith.rs ADD, SUBTRACT, MULTIPLY, @@ -42,6 +45,8 @@ public: NEGATION, NOT, + EQ, + PARTIAL_ORD, ADD_ASSIGN, SUB_ASSIGN, @@ -56,6 +61,7 @@ public: DEREF, DEREF_MUT, + RECEIVER, // https://github.com/rust-lang/rust/blob/master/library/core/src/ops/index.rs INDEX, @@ -82,6 +88,7 @@ public: COPY, CLONE, SIZED, + SYNC, // https://github.com/Rust-GCC/gccrs/issues/1896 // https://github.com/rust-lang/rust/commit/afbecc0f68c4dcfc4878ba5bcb1ac942544a1bdc @@ -116,16 +123,52 @@ public: STR, F32_RUNTIME, F64_RUNTIME, + + OPTION_SOME, + OPTION_NONE, + + RESULT_OK, + RESULT_ERR, + + INTOITER_INTOITER, + ITERATOR_NEXT, + + // NOTE: These lang items are *not* necessarily present in later versions of + // Rust (I am unsure at which point they have been removed as the `Try` + // trait is unstable). They will need to be changed when updating the + // targeted Rust version of gccrs + TRY, + TRY_INTO_RESULT, + TRY_FROM_ERROR, + TRY_FROM_OK, + + // NOTE: This is not a lang item in later versions of Rust + FROM_FROM, + + STRUCTURAL_PEQ, + STRUCTURAL_TEQ, + + DISCRIMINANT_TYPE, + DISCRIMINANT_KIND, + + MANUALLY_DROP, }; static const BiMap<std::string, Kind> lang_items; static tl::optional<Kind> Parse (const std::string &item); + static std::string ToString (Kind type); + static std::string PrettyString (Kind type); + static Kind OperatorToLangItem (ArithmeticOrLogicalOperator op); static Kind CompoundAssignmentOperatorToLangItem (ArithmeticOrLogicalOperator op); static Kind NegationOperatorToLangItem (NegationOperator op); + static Kind ComparisonToLangItem (ComparisonOperator op); + static std::string ComparisonToSegment (ComparisonOperator op); + + static bool IsEnumVariant (Kind type); }; } // namespace Rust diff --git a/gcc/rust/util/rust-operators.h b/gcc/rust/util/rust-operators.h index 608e771..02b1820 100644 --- a/gcc/rust/util/rust-operators.h +++ b/gcc/rust/util/rust-operators.h @@ -43,10 +43,10 @@ enum class ComparisonOperator { EQUAL, // std::cmp::PartialEq::eq NOT_EQUAL, // std::cmp::PartialEq::ne - GREATER_THAN, // std::cmp::PartialEq::gt - LESS_THAN, // std::cmp::PartialEq::lt - GREATER_OR_EQUAL, // std::cmp::PartialEq::ge - LESS_OR_EQUAL // std::cmp::PartialEq::le + GREATER_THAN, // std::cmp::PartialOrd::gt + LESS_THAN, // std::cmp::PartialOrd::lt + GREATER_OR_EQUAL, // std::cmp::PartialOrd::ge + LESS_OR_EQUAL // std::cmp::PartialOrd::le }; enum class LazyBooleanOperator diff --git a/gcc/rust/util/rust-stacked-contexts.h b/gcc/rust/util/rust-stacked-contexts.h index 39a0c08..b263d75 100644 --- a/gcc/rust/util/rust-stacked-contexts.h +++ b/gcc/rust/util/rust-stacked-contexts.h @@ -71,6 +71,20 @@ public: return last; } + const T &peek () const + { + rust_assert (!stack.empty ()); + + return stack.back (); + } + + T &peek () + { + rust_assert (!stack.empty ()); + + return stack.back (); + } + /** * Are we currently inside of a special context? */ diff --git a/gcc/rust/util/rust-token-converter.cc b/gcc/rust/util/rust-token-converter.cc index 220e891..fc34adb 100644 --- a/gcc/rust/util/rust-token-converter.cc +++ b/gcc/rust/util/rust-token-converter.cc @@ -18,8 +18,7 @@ #include "rust-token-converter.h" #include "bi-map.h" #include "line-map.h" - -#include <string> +#include "rust-system.h" namespace Rust { diff --git a/gcc/rust/util/rust-token-converter.h b/gcc/rust/util/rust-token-converter.h index 0498041..5405d6e 100644 --- a/gcc/rust/util/rust-token-converter.h +++ b/gcc/rust/util/rust-token-converter.h @@ -17,7 +17,7 @@ #ifndef RUST_TOKEN_CONVERTER_H #define RUST_TOKEN_CONVERTER_H -#include <vector> +#include "rust-system.h" #include "rust-token.h" #include "libproc_macro_internal/proc_macro.h" diff --git a/gcc/rust/util/rust-unwrap-segment.cc b/gcc/rust/util/rust-unwrap-segment.cc new file mode 100644 index 0000000..083a0e5 --- /dev/null +++ b/gcc/rust/util/rust-unwrap-segment.cc @@ -0,0 +1,61 @@ +// Copyright (C) 2025 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 "ast/rust-path.h" + +namespace Rust { + +NodeId +unwrap_segment_node_id (const AST::TypePathSegment &seg) +{ + return seg.get_node_id (); +} + +NodeId +unwrap_segment_node_id (const AST::SimplePathSegment &seg) +{ + return seg.get_node_id (); +} + +NodeId +unwrap_segment_node_id (const AST::PathExprSegment &seg) +{ + return seg.get_node_id (); +} + +tl::optional<LangItem::Kind> +unwrap_segment_get_lang_item (const AST::TypePathSegment &seg) +{ + if (seg.is_lang_item ()) + return seg.get_lang_item (); + return tl::nullopt; +} + +tl::optional<LangItem::Kind> +unwrap_segment_get_lang_item (const AST::SimplePathSegment &seg) +{ + return tl::nullopt; +} + +tl::optional<LangItem::Kind> +unwrap_segment_get_lang_item (const AST::PathExprSegment &seg) +{ + return tl::nullopt; +} + +} // namespace Rust diff --git a/gcc/rust/util/rust-unwrap-segment.h b/gcc/rust/util/rust-unwrap-segment.h new file mode 100644 index 0000000..bebdc3a --- /dev/null +++ b/gcc/rust/util/rust-unwrap-segment.h @@ -0,0 +1,121 @@ +// Copyright (C) 2025 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 <ast/rust-ast-full-decls.h> + +namespace Rust { + +/* + * Used to convert different path segment object references + * into SimplePathSegment/PathIdentSegment references + * + * unwrap_type_segment: + * expands to a call to unwrap_type_segment_inner::unwrap, + * used for type inference + */ +#define unwrap_type_segment(x) \ + (unwrap_type_segment_inner<typename std::remove_const< \ + typename std::remove_reference<decltype (x)>::type>::type>::unwrap (x)) + +template <class T> class unwrap_type_segment_inner; + +/* base case */ +template <> class unwrap_type_segment_inner<AST::SimplePathSegment> +{ +public: + /* The return type of unwrap */ + using ret = AST::SimplePathSegment; + + /* non-const qualified unwrap */ + static AST::SimplePathSegment &unwrap (AST::SimplePathSegment &x) + { + return x; + } + + /* const qualified unwrap */ + static const AST::SimplePathSegment &unwrap (const AST::SimplePathSegment &x) + { + return x; + } +}; + +/* case which dereferences unique_ptr */ +template <class T> class unwrap_type_segment_inner<std::unique_ptr<T>> +{ +public: + using ret = typename unwrap_type_segment_inner<T>::ret; + + static ret &unwrap (std::unique_ptr<T> &x) + { + return unwrap_type_segment (*x); + } + static const ret &unwrap (const std::unique_ptr<T> &x) + { + return unwrap_type_segment (*x); + } +}; + +/* case which handles objects with a get_ident_segment member function */ +template <class T> class unwrap_type_segment_inner +{ +public: + using ret = AST::PathIdentSegment; + + static ret &unwrap (T &x) { return x.get_ident_segment (); } + static const ret &unwrap (const T &x) { return x.get_ident_segment (); } +}; + +/* + * Used to get the node id of a path segment object + */ +NodeId +unwrap_segment_node_id (const AST::TypePathSegment &seg); + +NodeId +unwrap_segment_node_id (const AST::SimplePathSegment &seg); + +NodeId +unwrap_segment_node_id (const AST::PathExprSegment &seg); + +template <class T> +NodeId +unwrap_segment_node_id (const std::unique_ptr<T> &ptr) +{ + return unwrap_segment_node_id (*ptr); +} + +/** + * Used to check if a path segment is associated with a lang item + */ +tl::optional<LangItem::Kind> +unwrap_segment_get_lang_item (const AST::TypePathSegment &seg); + +tl::optional<LangItem::Kind> +unwrap_segment_get_lang_item (const AST::SimplePathSegment &seg); + +tl::optional<LangItem::Kind> +unwrap_segment_get_lang_item (const AST::PathExprSegment &seg); + +template <class T> +tl::optional<LangItem::Kind> +unwrap_segment_get_lang_item (const std::unique_ptr<T> &ptr) +{ + return unwrap_segment_get_lang_item (*ptr); +} + +} // namespace Rust |