diff options
Diffstat (limited to 'gcc/rust')
94 files changed, 2490 insertions, 374 deletions
diff --git a/gcc/rust/ChangeLog b/gcc/rust/ChangeLog index 64053d4..2a5219d 100644 --- a/gcc/rust/ChangeLog +++ b/gcc/rust/ChangeLog @@ -1,3 +1,520 @@ +2025-06-26 Martin Jambor <mjambor@suse.cz> + + * checks/errors/borrowck/rust-borrow-checker-diagnostics.cc + (BorrowCheckerDiagnostics::get_loan): Type cast loan to uint32_t. + +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 diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in index 4028b47..835e113 100644 --- a/gcc/rust/Make-lang.in +++ b/gcc/rust/Make-lang.in @@ -115,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 \ diff --git a/gcc/rust/ast/rust-ast-collector.cc b/gcc/rust/ast/rust-ast-collector.cc index 8ee6375..c850e96 100644 --- a/gcc/rust/ast/rust-ast-collector.cc +++ b/gcc/rust/ast/rust-ast-collector.cc @@ -491,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 ()); } } @@ -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 (); } } @@ -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 diff --git a/gcc/rust/ast/rust-ast-collector.h b/gcc/rust/ast/rust-ast-collector.h index b014c23..f45e3cc 100644 --- a/gcc/rust/ast/rust-ast-collector.h +++ b/gcc/rust/ast/rust-ast-collector.h @@ -303,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-visitor.cc b/gcc/rust/ast/rust-ast-visitor.cc index 9d524c3..b6833f6 100644 --- a/gcc/rust/ast/rust-ast-visitor.cc +++ b/gcc/rust/ast/rust-ast-visitor.cc @@ -82,7 +82,7 @@ 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 @@ -108,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 @@ -581,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 ()); } @@ -714,6 +715,16 @@ DefaultASTVisitor::visit (AST::InlineAsm &expr) } 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) { visit_outer_attrs (param); @@ -817,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); @@ -828,8 +847,9 @@ DefaultASTVisitor::visit (AST::Function &function) visit (function.get_qualifiers ()); for (auto &generic : function.get_generic_params ()) visit (generic); - 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 ()) diff --git a/gcc/rust/ast/rust-ast-visitor.h b/gcc/rust/ast/rust-ast-visitor.h index 51661df..b1fc504 100644 --- a/gcc/rust/ast/rust-ast-visitor.h +++ b/gcc/rust/ast/rust-ast-visitor.h @@ -131,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; @@ -241,6 +242,8 @@ public: class DefaultASTVisitor : public ASTVisitor { public: + virtual void visit_function_params (AST::Function &function); + virtual void visit (AST::Crate &crate); virtual void visit (AST::Token &tok) override; @@ -314,6 +317,7 @@ public: 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; diff --git a/gcc/rust/ast/rust-ast.cc b/gcc/rust/ast/rust-ast.cc index 06e0e7b..4e82be4 100644 --- a/gcc/rust/ast/rust-ast.cc +++ b/gcc/rust/ast/rust-ast.cc @@ -4651,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 09e0fce..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; @@ -1018,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 @@ -1263,6 +1269,7 @@ public: Await, AsyncBlock, InlineAsm, + LlvmInlineAsm, Identifier, FormatArgs, MacroInvocation, @@ -2095,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-expr.h b/gcc/rust/ast/rust-expr.h index 84cdfdb..fdb6360 100644 --- a/gcc/rust/ast/rust-expr.h +++ b/gcc/rust/ast/rust-expr.h @@ -3004,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) {} @@ -3013,15 +3017,11 @@ 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; } }; @@ -4885,6 +4885,27 @@ struct InlineAsmRegOrRegClass location_t locus; }; +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 InlineAsmOperand { public: @@ -5258,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) {} @@ -5330,6 +5352,77 @@ public: 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 } // namespace Rust diff --git a/gcc/rust/ast/rust-path.cc b/gcc/rust/ast/rust-path.cc index 69627be..8e43ddf 100644 --- a/gcc/rust/ast/rust-path.cc +++ b/gcc/rust/ast/rust-path.cc @@ -119,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; } diff --git a/gcc/rust/ast/rust-path.h b/gcc/rust/ast/rust-path.h index 805be8e..a4ba93b 100644 --- a/gcc/rust/ast/rust-path.h +++ b/gcc/rust/ast/rust-path.h @@ -167,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 (); @@ -222,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; } @@ -239,8 +231,6 @@ public: break; case Kind::Either: break; - case Kind::Error: - rust_unreachable (); } } @@ -283,8 +273,6 @@ public: { switch (get_kind ()) { - case Kind::Error: - rust_unreachable (); case Kind::Either: return "Ambiguous: " + path.as_string (); case Kind::Const: @@ -355,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) @@ -376,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; } @@ -389,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; diff --git a/gcc/rust/backend/rust-compile-asm.cc b/gcc/rust/backend/rust-compile-asm.cc index 22498bc..7351cf0 100644 --- a/gcc/rust/backend/rust-compile-asm.cc +++ b/gcc/rust/backend/rust-compile-asm.cc @@ -1,5 +1,7 @@ #include "rust-compile-asm.h" #include "rust-compile-expr.h" +#include "rust-system.h" + namespace Rust { namespace Compile { @@ -141,5 +143,57 @@ CompileAsm::asm_construct_label_tree (HIR::InlineAsm &expr) 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 index 4abd24e..22be94a 100644 --- a/gcc/rust/backend/rust-compile-asm.h +++ b/gcc/rust/backend/rust-compile-asm.h @@ -56,6 +56,20 @@ public: 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-block.h b/gcc/rust/backend/rust-compile-block.h index 37e3980..3f38d08 100644 --- a/gcc/rust/backend/rust-compile-block.h +++ b/gcc/rust/backend/rust-compile-block.h @@ -100,6 +100,7 @@ public: 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) @@ -182,6 +183,7 @@ public: 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-expr.cc b/gcc/rust/backend/rust-compile-expr.cc index 37856a7..dd3420f 100644 --- a/gcc/rust/backend/rust-compile-expr.cc +++ b/gcc/rust/backend/rust-compile-expr.cc @@ -368,6 +368,13 @@ CompileExpr::visit (HIR::InlineAsm &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; @@ -1965,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); diff --git a/gcc/rust/backend/rust-compile-expr.h b/gcc/rust/backend/rust-compile-expr.h index dc78dee..65ed4b3 100644 --- a/gcc/rust/backend/rust-compile-expr.h +++ b/gcc/rust/backend/rust-compile-expr.h @@ -69,6 +69,7 @@ public: 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 {} 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 d6acc6a..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 @@ -325,6 +325,10 @@ ExprStmtBuilder::visit (HIR::InlineAsm &expr) {} void +ExprStmtBuilder::visit (HIR::LlvmInlineAsm &expr) +{} + +void ExprStmtBuilder::visit (HIR::MethodCallExpr &expr) {} 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 daedb68..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 @@ -100,6 +100,7 @@ protected: // Expr 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::MatchExpr &expr) override; void visit (HIR::AwaitExpr &expr) override; 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 3bc622c..b7a1555 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h @@ -207,6 +207,7 @@ public: } 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-struct.h b/gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h index 94fcecd..84311cc 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h @@ -153,6 +153,7 @@ protected: 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 diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-place.h b/gcc/rust/checks/errors/borrowck/rust-bir-place.h index 67ca90b..dd9e672 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-place.h +++ b/gcc/rust/checks/errors/borrowck/rust-bir-place.h @@ -204,6 +204,9 @@ 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); } @@ -219,7 +222,11 @@ public: internal_vector.emplace_back (std::forward<Args> (args)...); } - size_t size () const { return internal_vector.size (); } + 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; } }; @@ -418,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 diff --git a/gcc/rust/checks/errors/borrowck/rust-bir.h b/gcc/rust/checks/errors/borrowck/rust-bir.h index e90e508..8a5f7be 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir.h +++ b/gcc/rust/checks/errors/borrowck/rust-bir.h @@ -35,6 +35,26 @@ using BasicBlocks = IndexVec<BasicBlockId, BasicBlock>; class Statement; class AbstractExpr; +/** 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). * It represents a single function (method, closure, etc.), which is the @@ -132,26 +152,6 @@ public: WARN_UNUSED_RESULT location_t get_location () const { return location; } }; -/** 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}; - struct BasicBlock { // BIR "instructions". 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 6c67706..adf1448 100644 --- a/gcc/rust/checks/errors/borrowck/rust-borrow-checker-diagnostics.cc +++ b/gcc/rust/checks/errors/borrowck/rust-borrow-checker-diagnostics.cc @@ -142,7 +142,7 @@ BorrowCheckerDiagnostics::get_statement (Polonius::Point point) const BIR::Loan & BorrowCheckerDiagnostics::get_loan (Polonius::Loan loan) { - return bir_function.place_db.get_loans ()[{loan}]; + return bir_function.place_db.get_loans ()[{(uint32_t) loan}]; } const HIR::LifetimeParam * diff --git a/gcc/rust/checks/errors/borrowck/rust-function-collector.h b/gcc/rust/checks/errors/borrowck/rust-function-collector.h index cdb20e8..7cf0952 100644 --- a/gcc/rust/checks/errors/borrowck/rust-function-collector.h +++ b/gcc/rust/checks/errors/borrowck/rust-function-collector.h @@ -123,6 +123,7 @@ public: 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 {} diff --git a/gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc b/gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc index a537c42..2a10053 100644 --- a/gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc +++ b/gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc @@ -306,6 +306,10 @@ PrivacyReporter::visit (HIR::InlineAsm &) {} void +PrivacyReporter::visit (HIR::LlvmInlineAsm &) +{} + +void PrivacyReporter::visit (HIR::TypePath &path) { check_for_privacy_violation (path.get_mappings ().get_nodeid (), diff --git a/gcc/rust/checks/errors/privacy/rust-privacy-reporter.h b/gcc/rust/checks/errors/privacy/rust-privacy-reporter.h index 5111a3e..7df2cf4 100644 --- a/gcc/rust/checks/errors/privacy/rust-privacy-reporter.h +++ b/gcc/rust/checks/errors/privacy/rust-privacy-reporter.h @@ -125,6 +125,7 @@ types 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/rust-const-checker.cc b/gcc/rust/checks/errors/rust-const-checker.cc index 4904322..3716ea5 100644 --- a/gcc/rust/checks/errors/rust-const-checker.cc +++ b/gcc/rust/checks/errors/rust-const-checker.cc @@ -537,6 +537,10 @@ ConstChecker::visit (InlineAsm &) {} void +ConstChecker::visit (LlvmInlineAsm &) +{} + +void ConstChecker::visit (TypeParam &) {} @@ -646,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 diff --git a/gcc/rust/checks/errors/rust-const-checker.h b/gcc/rust/checks/errors/rust-const-checker.h index 00f57988..b954330 100644 --- a/gcc/rust/checks/errors/rust-const-checker.h +++ b/gcc/rust/checks/errors/rust-const-checker.h @@ -132,6 +132,7 @@ private: 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; diff --git a/gcc/rust/checks/errors/rust-hir-pattern-analysis.cc b/gcc/rust/checks/errors/rust-hir-pattern-analysis.cc index 257f4cd..648bc07 100644 --- a/gcc/rust/checks/errors/rust-hir-pattern-analysis.cc +++ b/gcc/rust/checks/errors/rust-hir-pattern-analysis.cc @@ -423,6 +423,10 @@ PatternChecker::visit (InlineAsm &expr) {} void +PatternChecker::visit (LlvmInlineAsm &expr) +{} + +void PatternChecker::visit (TypeParam &) {} diff --git a/gcc/rust/checks/errors/rust-hir-pattern-analysis.h b/gcc/rust/checks/errors/rust-hir-pattern-analysis.h index 2171340..6d60ced 100644 --- a/gcc/rust/checks/errors/rust-hir-pattern-analysis.h +++ b/gcc/rust/checks/errors/rust-hir-pattern-analysis.h @@ -106,6 +106,7 @@ private: 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; diff --git a/gcc/rust/checks/errors/rust-unsafe-checker.cc b/gcc/rust/checks/errors/rust-unsafe-checker.cc index 8aa59ee..46eef11 100644 --- a/gcc/rust/checks/errors/rust-unsafe-checker.cc +++ b/gcc/rust/checks/errors/rust-unsafe-checker.cc @@ -481,9 +481,14 @@ 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); + // 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), @@ -666,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 &) {} diff --git a/gcc/rust/checks/errors/rust-unsafe-checker.h b/gcc/rust/checks/errors/rust-unsafe-checker.h index 63098fe..9a8fb7c 100644 --- a/gcc/rust/checks/errors/rust-unsafe-checker.h +++ b/gcc/rust/checks/errors/rust-unsafe-checker.h @@ -114,6 +114,7 @@ private: 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; diff --git a/gcc/rust/expand/rust-derive-clone.cc b/gcc/rust/expand/rust-derive-clone.cc index a955b58..321fa00 100644 --- a/gcc/rust/expand/rust-derive-clone.cc +++ b/gcc/rust/expand/rust-derive-clone.cc @@ -293,8 +293,14 @@ DeriveClone::clone_enum_struct (PathInExpression variant_path, 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 (variant_path, std::move (cloned_fields), loc)); + new StructExprStructFields (new_path, std::move (cloned_fields), loc)); return builder.match_case (std::move (pattern), std::move (expr)); } diff --git a/gcc/rust/expand/rust-derive.h b/gcc/rust/expand/rust-derive.h index d8cc0a4..5fca49c 100644 --- a/gcc/rust/expand/rust-derive.h +++ b/gcc/rust/expand/rust-derive.h @@ -171,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-visitor.cc b/gcc/rust/expand/rust-expand-visitor.cc index d4db313..42df5e1 100644 --- a/gcc/rust/expand/rust-expand-visitor.cc +++ b/gcc/rust/expand/rust-expand-visitor.cc @@ -489,7 +489,8 @@ ExpandVisitor::visit (AST::PathInExpression &path) void ExpandVisitor::visit (AST::TypePathSegmentGeneric &segment) { - expand_generic_args (segment.get_generic_args ()); + if (segment.has_generic_args ()) + expand_generic_args (segment.get_generic_args ()); } void diff --git a/gcc/rust/expand/rust-macro-builtins-asm.cc b/gcc/rust/expand/rust-macro-builtins-asm.cc index 4d02604..e255729 100644 --- a/gcc/rust/expand/rust-macro-builtins-asm.cc +++ b/gcc/rust/expand/rust-macro-builtins-asm.cc @@ -22,6 +22,7 @@ #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{ @@ -660,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) { @@ -671,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) @@ -962,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 8081dae..bd64a7f 100644 --- a/gcc/rust/expand/rust-macro-builtins-asm.h +++ b/gcc/rust/expand/rust-macro-builtins-asm.h @@ -172,4 +172,36 @@ tl::optional<std::string> parse_label (Parser<MacroInvocLexer> &parser, TokenId last_token_id, InlineAsmContext &inline_asm_ctx); +// 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.cc b/gcc/rust/expand/rust-macro-builtins.cc index 39c4c46..b58ed71 100644 --- a/gcc/rust/expand/rust-macro-builtins.cc +++ b/gcc/rust/expand/rust-macro-builtins.cc @@ -83,7 +83,6 @@ const BiMap<std::string, BuiltinMacro> MacroBuiltin::builtins = {{ {"Ord", BuiltinMacro::Ord}, {"PartialOrd", BuiltinMacro::PartialOrd}, {"Hash", BuiltinMacro::Hash}, - }}; AST::MacroTranscriberFunc @@ -104,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}, @@ -122,7 +130,7 @@ std::unordered_map<std::string, AST::MacroTranscriberFunc> {"format_args_nl", format_args_maker (AST::FormatArgs::Newline::Yes)}, {"asm", inline_asm_maker (AST::AsmKind::Inline)}, // FIXME: Is that okay? - {"llvm_asm", inline_asm_maker (AST::AsmKind::Inline)}, + {"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 */ @@ -137,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 ff06ebf..541e956 100644 --- a/gcc/rust/expand/rust-macro-builtins.h +++ b/gcc/rust/expand/rust-macro-builtins.h @@ -181,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 cd17a3f..673b8fb 100644 --- a/gcc/rust/expand/rust-macro-expand.cc +++ b/gcc/rust/expand/rust-macro-expand.cc @@ -28,6 +28,7 @@ #include "rust-cfg-strip.h" #include "rust-early-name-resolver.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; @@ -621,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; @@ -650,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 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 5039798..2d9a445 100644 --- a/gcc/rust/hir/rust-ast-lower-base.cc +++ b/gcc/rust/hir/rust-ast-lower-base.cc @@ -267,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 &) {} diff --git a/gcc/rust/hir/rust-ast-lower-base.h b/gcc/rust/hir/rust-ast-lower-base.h index b3bb174..3116181 100644 --- a/gcc/rust/hir/rust-ast-lower-base.h +++ b/gcc/rust/hir/rust-ast-lower-base.h @@ -152,6 +152,7 @@ public: 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; diff --git a/gcc/rust/hir/rust-ast-lower-expr.cc b/gcc/rust/hir/rust-ast-lower-expr.cc index 3784e74..07d0c835 100644 --- a/gcc/rust/hir/rust-ast-lower-expr.cc +++ b/gcc/rust/hir/rust-ast-lower-expr.cc @@ -955,6 +955,50 @@ ASTLoweringExpr::visit (AST::InlineAsm &expr) 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 af60e01..adedeb3 100644 --- a/gcc/rust/hir/rust-ast-lower-expr.h +++ b/gcc/rust/hir/rust-ast-lower-expr.h @@ -122,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-type.cc b/gcc/rust/hir/rust-ast-lower-type.cc index d3e528d..a678f18 100644 --- a/gcc/rust/hir/rust-ast-lower-type.cc +++ b/gcc/rust/hir/rust-ast-lower-type.cc @@ -557,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), diff --git a/gcc/rust/hir/rust-hir-dump.cc b/gcc/rust/hir/rust-hir-dump.cc index dafa823..cb32f68 100644 --- a/gcc/rust/hir/rust-hir-dump.cc +++ b/gcc/rust/hir/rust-hir-dump.cc @@ -1284,7 +1284,9 @@ Dump::visit (BlockExpr &e) do_expr (e); do_inner_attrs (e); put_field ("tail_reachable", std::to_string (e.is_tail_reachable ())); - put_field ("label", e.get_label ().as_string ()); + + if (e.has_label ()) + put_field ("label", e.get_label ().as_string ()); visit_collection ("statements", e.get_statements ()); @@ -1508,6 +1510,10 @@ Dump::visit (InlineAsm &e) {} void +Dump::visit (LlvmInlineAsm &e) +{} + +void Dump::visit (TypeParam &e) { begin ("TypeParam"); diff --git a/gcc/rust/hir/rust-hir-dump.h b/gcc/rust/hir/rust-hir-dump.h index afcd668..45b1708 100644 --- a/gcc/rust/hir/rust-hir-dump.h +++ b/gcc/rust/hir/rust-hir-dump.h @@ -166,6 +166,7 @@ private: 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; diff --git a/gcc/rust/hir/tree/rust-hir-expr-abstract.h b/gcc/rust/hir/tree/rust-hir-expr-abstract.h index ecf9bd1..5bc5d89 100644 --- a/gcc/rust/hir/tree/rust-hir-expr-abstract.h +++ b/gcc/rust/hir/tree/rust-hir-expr-abstract.h @@ -71,6 +71,7 @@ public: AsyncBlock, Path, InlineAsm, + LlvmInlineAsm, }; BaseKind get_hir_kind () override final { return Node::BaseKind::EXPR; } diff --git a/gcc/rust/hir/tree/rust-hir-expr.h b/gcc/rust/hir/tree/rust-hir-expr.h index 96f0cf6..375f474 100644 --- a/gcc/rust/hir/tree/rust-hir-expr.h +++ b/gcc/rust/hir/tree/rust-hir-expr.h @@ -3118,6 +3118,80 @@ public: 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 6c19f24..1e313ec 100644 --- a/gcc/rust/hir/tree/rust-hir-full-decls.h +++ b/gcc/rust/hir/tree/rust-hir-full-decls.h @@ -126,6 +126,7 @@ class InlineAsmRegClass; struct AnonConst; class InlineAsmOperand; class InlineAsm; +class LlvmInlineAsm; // rust-stmt.h class EmptyStmt; diff --git a/gcc/rust/hir/tree/rust-hir-item.h b/gcc/rust/hir/tree/rust-hir-item.h index b9b105b..37f599c 100644 --- a/gcc/rust/hir/tree/rust-hir-item.h +++ b/gcc/rust/hir/tree/rust-hir-item.h @@ -2070,6 +2070,8 @@ public: Identifier get_name () const { return name; } + bool has_type () const { return expr != nullptr; } + bool has_expr () const { return expr != nullptr; } Type &get_type () diff --git a/gcc/rust/hir/tree/rust-hir-visitor.h b/gcc/rust/hir/tree/rust-hir-visitor.h index 800e647..283cc34 100644 --- a/gcc/rust/hir/tree/rust-hir-visitor.h +++ b/gcc/rust/hir/tree/rust-hir-visitor.h @@ -84,6 +84,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; virtual void visit (TypeParam ¶m) = 0; virtual void visit (ConstGenericParam ¶m) = 0; virtual void visit (LifetimeWhereClauseItem &item) = 0; @@ -220,6 +221,7 @@ public: 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 {} @@ -441,6 +443,7 @@ public: virtual void visit (IfExpr &expr) = 0; virtual void visit (IfExprConseqElse &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 c8bf9da..093d8d5 100644 --- a/gcc/rust/hir/tree/rust-hir.cc +++ b/gcc/rust/hir/tree/rust-hir.cc @@ -3822,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); diff --git a/gcc/rust/parse/rust-parse-impl.h b/gcc/rust/parse/rust-parse-impl.h index 3bb758e..9dda231 100644 --- a/gcc/rust/parse/rust-parse-impl.h +++ b/gcc/rust/parse/rust-parse-impl.h @@ -3174,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> ( @@ -6249,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 (); @@ -6270,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) { @@ -6287,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 (), @@ -6313,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)); } @@ -6383,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? diff --git a/gcc/rust/parse/rust-parse.h b/gcc/rust/parse/rust-parse.h index ff79879..827d91d 100644 --- a/gcc/rust/parse/rust-parse.h +++ b/gcc/rust/parse/rust-parse.h @@ -226,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); diff --git a/gcc/rust/resolve/rust-ast-resolve-base.cc b/gcc/rust/resolve/rust-ast-resolve-base.cc index 6c35a22..b781ce33 100644 --- a/gcc/rust/resolve/rust-ast-resolve-base.cc +++ b/gcc/rust/resolve/rust-ast-resolve-base.cc @@ -328,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 ab74e84..5bb9e4f 100644 --- a/gcc/rust/resolve/rust-ast-resolve-base.h +++ b/gcc/rust/resolve/rust-ast-resolve-base.h @@ -110,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 8070fc1..6242235 100644 --- a/gcc/rust/resolve/rust-ast-resolve-expr.cc +++ b/gcc/rust/resolve/rust-ast-resolve-expr.cc @@ -368,6 +368,17 @@ 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) { diff --git a/gcc/rust/resolve/rust-ast-resolve-expr.h b/gcc/rust/resolve/rust-ast-resolve-expr.h index 562a3bd..b296d66 100644 --- a/gcc/rust/resolve/rust-ast-resolve-expr.h +++ b/gcc/rust/resolve/rust-ast-resolve-expr.h @@ -57,6 +57,7 @@ public: 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; diff --git a/gcc/rust/resolve/rust-ast-resolve-item.cc b/gcc/rust/resolve/rust-ast-resolve-item.cc index d584961..30f6d43 100644 --- a/gcc/rust/resolve/rust-ast-resolve-item.cc +++ b/gcc/rust/resolve/rust-ast-resolve-item.cc @@ -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 diff --git a/gcc/rust/resolve/rust-ast-resolve-path.cc b/gcc/rust/resolve/rust-ast-resolve-path.cc index 530926d..fb6715d 100644 --- a/gcc/rust/resolve/rust-ast-resolve-path.cc +++ b/gcc/rust/resolve/rust-ast-resolve-path.cc @@ -68,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, - "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 UNKNOWN_NODEID; } @@ -372,8 +371,9 @@ ResolvePath::resolve_path (AST::SimplePath &expr) { if (!is_first_segment) { - rust_error_at (segment.get_locus (), - "%<super%> can only be used in start position"); + 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) diff --git a/gcc/rust/resolve/rust-ast-resolve-type.cc b/gcc/rust/resolve/rust-ast-resolve-type.cc index 606141c..8fd69c3 100644 --- a/gcc/rust/resolve/rust-ast-resolve-type.cc +++ b/gcc/rust/resolve/rust-ast-resolve-type.cc @@ -176,8 +176,7 @@ ResolveRelativeTypePath::go (AST::TypePath &path, NodeId &resolved_node_id) if (in_middle_of_path && segment->is_lower_self_seg ()) { rust_error_at (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 false; } diff --git a/gcc/rust/resolve/rust-ast-resolve-type.h b/gcc/rust/resolve/rust-ast-resolve-type.h index 8379d0e..f1481fc 100644 --- a/gcc/rust/resolve/rust-ast-resolve-type.h +++ b/gcc/rust/resolve/rust-ast-resolve-type.h @@ -141,8 +141,8 @@ public: if (first_pass) ResolveType::go (param.get_type ()); else if (param.has_default_value ()) - ResolveExpr::go (param.get_default_value ().get_expression (), prefix, - canonical_prefix); + ResolveExpr::go (param.get_default_value_unchecked ().get_expression (), + prefix, canonical_prefix); } void visit (AST::TypeParam ¶m) override diff --git a/gcc/rust/resolve/rust-default-resolver.cc b/gcc/rust/resolve/rust-default-resolver.cc index 7528e79..480034c 100644 --- a/gcc/rust/resolve/rust-default-resolver.cc +++ b/gcc/rust/resolve/rust-default-resolver.cc @@ -179,5 +179,13 @@ DefaultResolver::visit (AST::StaticItem &item) ctx.scoped (Rib::Kind::ConstantItem, item.get_node_id (), expr_vis); } +void +DefaultResolver::visit (AST::TypeParam ¶m) +{ + auto expr_vis = [this, ¶m] () { AST::DefaultASTVisitor::visit (param); }; + + 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 587d7d4..2a987ef 100644 --- a/gcc/rust/resolve/rust-default-resolver.h +++ b/gcc/rust/resolve/rust-default-resolver.h @@ -50,6 +50,8 @@ public: 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 &) override; void visit (AST::TupleStruct &) override; 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 afaca1f..3390f09 100644 --- a/gcc/rust/resolve/rust-early-name-resolver-2.0.cc +++ b/gcc/rust/resolve/rust-early-name-resolver-2.0.cc @@ -70,8 +70,7 @@ Early::go (AST::Crate &crate) bool Early::resolve_glob_import (NodeId use_dec_id, TopLevel::ImportKind &&glob) { - auto resolved - = ctx.resolve_path (glob.to_resolve.get_segments (), Namespace::Types); + auto resolved = ctx.resolve_path (glob.to_resolve, Namespace::Types); if (!resolved.has_value ()) return false; @@ -141,6 +140,10 @@ Early::build_import_mapping ( // 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: @@ -154,7 +157,7 @@ Early::build_import_mapping ( break; } - if (!found) + 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 ())); @@ -325,10 +328,9 @@ Early::visit_attributes (std::vector<AST::Attribute> &attrs) 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 () 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 c4226fe..e78bec0 100644 --- a/gcc/rust/resolve/rust-early-name-resolver-2.0.h +++ b/gcc/rust/resolve/rust-early-name-resolver-2.0.h @@ -218,7 +218,6 @@ private: std::vector<std::pair<Rib::Definition, Namespace>> resolve_path_in_all_ns (const P &path) { - const auto &segments = path.get_segments (); std::vector<std::pair<Rib::Definition, Namespace>> resolved; // Pair a definition with the namespace it was found in @@ -229,13 +228,22 @@ private: }; }; - ctx.resolve_path (segments, Namespace::Values) + 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 (segments, Namespace::Types) + ctx.resolve_path (path, type_errors, Namespace::Types) .map (pair_with_ns (Namespace::Types)); - ctx.resolve_path (segments, Namespace::Macros) + 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; } diff --git a/gcc/rust/resolve/rust-forever-stack.h b/gcc/rust/resolve/rust-forever-stack.h index cf02651..81468e5 100644 --- a/gcc/rust/resolve/rust-forever-stack.h +++ b/gcc/rust/resolve/rust-forever-stack.h @@ -673,7 +673,8 @@ public: template <typename S> 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::function<void (const S &, NodeId)> insert_segment_resolution, + std::vector<Error> &collect_errors); // FIXME: Documentation tl::optional<Resolver::CanonicalPath> to_canonical_path (NodeId id) const; @@ -792,13 +793,15 @@ private: 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::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, - std::function<void (const S &, NodeId)> insert_segment_resolution); + 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, @@ -828,6 +831,21 @@ private: 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 993e2d4..069111e 100644 --- a/gcc/rust/resolve/rust-forever-stack.hxx +++ b/gcc/rust/resolve/rust-forever-stack.hxx @@ -398,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; @@ -419,7 +420,8 @@ template <typename S> tl::optional<typename std::vector<S>::const_iterator> 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::function<void (const S &, NodeId)> insert_segment_resolution, + std::vector<Error> &collect_errors) { auto iterator = segments.begin (); @@ -436,8 +438,9 @@ ForeverStack<N>::find_starting_point ( // 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 ()) @@ -460,8 +463,9 @@ ForeverStack<N>::find_starting_point ( 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; } @@ -487,7 +491,8 @@ 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, - std::function<void (const S &, NodeId)> insert_segment_resolution) + std::function<void (const S &, NodeId)> insert_segment_resolution, + std::vector<Error> &collect_errors) { Node *current_node = &starting_point; for (; !is_last (iterator, segments); iterator++) @@ -509,9 +514,10 @@ ForeverStack<N>::resolve_segments ( 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; @@ -620,7 +626,8 @@ template <typename S> tl::optional<Rib::Definition> ForeverStack<N>::resolve_path ( const std::vector<S> &segments, bool has_opening_scope_resolution, - std::function<void (const S &, NodeId)> insert_segment_resolution) + std::function<void (const S &, NodeId)> insert_segment_resolution, + std::vector<Error> &collect_errors) { // TODO: What to do if segments.empty() ? @@ -668,15 +675,16 @@ ForeverStack<N>::resolve_path ( std::reference_wrapper<Node> starting_point = cursor (); auto res - = find_starting_point (segments, starting_point, insert_segment_resolution) + = find_starting_point (segments, starting_point, insert_segment_resolution, + collect_errors) .and_then ( - [this, &segments, &starting_point, &insert_segment_resolution] ( - typename std::vector<S>::const_iterator iterator) { + [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); + insert_segment_resolution, collect_errors); }) .and_then ([this, &segments, &insert_segment_resolution] ( - Node final_node) -> tl::optional<Rib::Definition> { + 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; 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 f743e1e..6ec0422 100644 --- a/gcc/rust/resolve/rust-late-name-resolver-2.0.cc +++ b/gcc/rust/resolve/rust-late-name-resolver-2.0.cc @@ -129,6 +129,54 @@ 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) { DefaultASTVisitor::visit_outer_attrs (let); @@ -138,8 +186,13 @@ Late::visit (AST::LetStmt &let) // 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 ()); @@ -167,9 +220,68 @@ Late::visit (AST::IdentifierPattern &identifier) // but values does not allow shadowing... since functions cannot shadow // do we insert functions in labels as well? + 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 (identifier.get_ident (), - identifier.get_node_id ()); + std::ignore = ctx.values.insert_shadowable (field.get_identifier (), + field.get_node_id ()); } void @@ -347,8 +459,8 @@ Late::visit (AST::PathInExpression &expr) if (!resolved) { if (!ctx.lookup (expr.get_segments ().front ().get_node_id ())) - rust_error_at (expr.get_locus (), - "could not resolve path expression: %qs", + rust_error_at (expr.get_locus (), ErrorCode::E0433, + "Cannot find path %qs in this scope", expr.as_simple_path ().as_string ().c_str ()); return; } @@ -393,6 +505,14 @@ Late::visit (AST::TypePath &type) 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 ())); } @@ -509,14 +629,35 @@ void Late::visit (AST::ClosureExprInner &closure) { add_captures (closure, ctx); - DefaultResolver::visit (closure); + + 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); - DefaultResolver::visit (closure); + + visit_outer_attrs (closure); + + ctx.bindings.enter (BindingSource::Param); + + for (auto ¶m : closure.get_params ()) + visit (param); + + ctx.bindings.exit (); + + 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 5703b15..171d9bf 100644 --- a/gcc/rust/resolve/rust-late-name-resolver-2.0.h +++ b/gcc/rust/resolve/rust-late-name-resolver-2.0.h @@ -37,12 +37,20 @@ 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; diff --git a/gcc/rust/resolve/rust-name-resolution-context.cc b/gcc/rust/resolve/rust-name-resolution-context.cc index 92c4863..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 ()) {} diff --git a/gcc/rust/resolve/rust-name-resolution-context.h b/gcc/rust/resolve/rust-name-resolution-context.h index 84c0800..19ba750 100644 --- a/gcc/rust/resolve/rust-name-resolution-context.h +++ b/gcc/rust/resolve/rust-name-resolution-context.h @@ -23,6 +23,7 @@ #include "rust-forever-stack.h" #include "rust-hir-map.h" #include "rust-rib.h" +#include "rust-stacked-contexts.h" namespace Rust { namespace Resolver2_0 { @@ -156,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 { @@ -212,6 +269,7 @@ public: ForeverStack<Namespace::Labels> labels; Analysis::Mappings &mappings; + StackedContexts<BindingLayer> bindings; // TODO: Rename // TODO: Use newtype pattern for Usage and Definition @@ -220,9 +278,10 @@ public: 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, - Namespace ns) + 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) { @@ -234,60 +293,102 @@ public: { case Namespace::Values: return values.resolve_path (segments, has_opening_scope_resolution, - insert_segment_resolution); + insert_segment_resolution, collect_errors); case Namespace::Types: return types.resolve_path (segments, has_opening_scope_resolution, - insert_segment_resolution); + insert_segment_resolution, collect_errors); case Namespace::Macros: return macros.resolve_path (segments, has_opening_scope_resolution, - insert_segment_resolution); + insert_segment_resolution, collect_errors); case Namespace::Labels: return labels.resolve_path (segments, has_opening_scope_resolution, - insert_segment_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, - Args... ns_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_args...}; + std::initializer_list<Namespace> namespaces = {ns_first, ns_args...}; for (auto ns : namespaces) { - if (auto ret - = resolve_path (segments, has_opening_scope_resolution, ns)) + 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, - Args... ns_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 (), ns_args...); + path.has_opening_scope_resolution (), collect_errors, + ns_first, ns_args...); } template <typename... Args> - tl::optional<Rib::Definition> resolve_path (const AST::PathInExpression &path, - Args... ns_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 (), - ns_args...); + collect_errors, ns_first, ns_args...); } template <typename... Args> - tl::optional<Rib::Definition> resolve_path (const AST::TypePath &path, - Args... ns_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 (), ns_args...); + 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: 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 8863be7..2f036fe 100644 --- a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc +++ b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc @@ -113,7 +113,17 @@ TopLevel::visit (AST::Module &module) // This was copied from the old early resolver method // 'accumulate_escaped_macros' if (module.get_kind () == AST::Module::UNLOADED) - module.load_items (); + { + module.load_items (); + + // 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); @@ -125,8 +135,7 @@ TopLevel::visit (AST::Module &module) void TopLevel::visit (AST::Trait &trait) { - insert_or_error_out (trait.get_identifier ().as_string (), trait, - Namespace::Types); + insert_or_error_out (trait.get_identifier (), trait, Namespace::Types); DefaultResolver::visit (trait); } @@ -538,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 diff --git a/gcc/rust/rust-gcc.cc b/gcc/rust/rust-gcc.cc index 72aef08..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); @@ -613,14 +607,13 @@ fill_in_fields (tree fill, const std::vector<typed_identifier> &fields, { 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); @@ -652,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); @@ -684,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 @@ -714,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; @@ -732,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); } @@ -742,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); } @@ -752,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); @@ -773,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); @@ -794,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; @@ -845,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; @@ -878,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); @@ -895,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); @@ -909,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); @@ -923,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); @@ -1021,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. @@ -1035,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 @@ -1071,7 +1062,7 @@ 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 @@ -1118,6 +1109,7 @@ arithmetic_or_logical_expression (ArithmeticOrLogicalOperator op, tree left, 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"); @@ -1182,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)` @@ -1222,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. */ @@ -1242,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 @@ -1263,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; @@ -1305,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) @@ -1336,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) @@ -1376,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 ()); @@ -1393,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) @@ -1497,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 @@ -1520,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))); @@ -1600,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); @@ -1631,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 @@ -1656,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 @@ -1681,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) @@ -1701,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); @@ -1728,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. @@ -1752,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); } @@ -1808,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; @@ -1832,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); } @@ -1914,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) @@ -1944,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. @@ -1983,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; @@ -2008,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); @@ -2029,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); @@ -2046,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); @@ -2080,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 (); @@ -2198,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); @@ -2242,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) @@ -2275,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; @@ -2309,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); @@ -2333,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-session-manager.cc b/gcc/rust/rust-session-manager.cc index 15f21ef..48acbf34 100644 --- a/gcc/rust/rust-session-manager.cc +++ b/gcc/rust/rust-session-manager.cc @@ -611,7 +611,6 @@ Session::compile_crate (const char *filename) return; AST::CollectLangItems ().go (parsed_crate); - AST::DesugarQuestionMark ().go (parsed_crate); auto name_resolution_ctx = Resolver2_0::NameResolutionContext (); // expansion pipeline stage @@ -619,6 +618,7 @@ Session::compile_crate (const char *filename) 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)) diff --git a/gcc/rust/typecheck/rust-hir-trait-resolve.cc b/gcc/rust/typecheck/rust-hir-trait-resolve.cc index e78c192..032bb58 100644 --- a/gcc/rust/typecheck/rust-hir-trait-resolve.cc +++ b/gcc/rust/typecheck/rust-hir-trait-resolve.cc @@ -384,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 diff --git a/gcc/rust/typecheck/rust-hir-type-check-base.cc b/gcc/rust/typecheck/rust-hir-type-check-base.cc index beee91e..14b8ab8 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-base.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-base.cc @@ -308,7 +308,8 @@ TypeCheckBase::parse_repr_options (const AST::AttrVec &attrs, location_t locus) repr.pack = 0; repr.align = 0; - // FIXME handle repr types.... + // 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); @@ -353,13 +354,29 @@ TypeCheckBase::parse_repr_options (const AST::AttrVec &attrs, location_t locus) // 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 @@ -379,9 +396,28 @@ 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; diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.cc b/gcc/rust/typecheck/rust-hir-type-check-expr.cc index 791795f..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,8 @@ // 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" @@ -842,6 +844,19 @@ TypeCheckExpr::visit (HIR::InlineAsm &expr) } 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; @@ -1127,33 +1142,119 @@ 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 (), ErrorCode::E0609, - "no field %qs on type %qs", + 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) { @@ -1181,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 ()); @@ -1219,10 +1311,10 @@ TypeCheckExpr::visit (HIR::MethodCallExpr &expr) HirId autoderef_mappings_id = 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 () @@ -1249,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 ()) { diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.h b/gcc/rust/typecheck/rust-hir-type-check-expr.h index 2a0022c..79121b3 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-expr.h +++ b/gcc/rust/typecheck/rust-hir-type-check-expr.h @@ -70,6 +70,7 @@ public: 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 {} diff --git a/gcc/rust/typecheck/rust-hir-type-check-item.cc b/gcc/rust/typecheck/rust-hir-type-check-item.cc index 9774921..aaa04af 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-item.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-item.cc @@ -355,6 +355,18 @@ TypeCheckItem::visit (HIR::Enum &enum_decl) 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 tl::optional<CanonicalPath> canonical_path; @@ -637,6 +649,38 @@ TypeCheckItem::visit (HIR::Function &function) context->switch_to_fn_body (); 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_locus (); 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 800f7ca..7e3a57a 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-struct-field.h +++ b/gcc/rust/typecheck/rust-hir-type-check-struct-field.h @@ -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 40c42b2..df1636a 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-struct.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-struct.cc @@ -28,7 +28,7 @@ TypeCheckStructExpr::TypeCheckStructExpr (HIR::Expr &e) : TypeCheckBase (), 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 * @@ -65,7 +65,7 @@ TypeCheckStructExpr::resolve (HIR::StructExprStructFields &struct_expr) if (base_unify->get_kind () != struct_path_ty->get_kind ()) { - rust_fatal_error ( + rust_error_at ( struct_expr.get_struct_base ().get_base ().get_locus (), "incompatible types for base struct reference"); return; @@ -82,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); @@ -118,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; @@ -271,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); @@ -317,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); diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc index efad5f6..f0f4a07 100644 --- a/gcc/rust/typecheck/rust-tyty.cc +++ b/gcc/rust/typecheck/rust-tyty.cc @@ -682,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 { diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h index e814f07..1cada9a 100644 --- a/gcc/rust/typecheck/rust-tyty.h +++ b/gcc/rust/typecheck/rust-tyty.h @@ -137,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; @@ -711,12 +714,22 @@ 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 diff --git a/gcc/rust/util/rust-attribute-values.h b/gcc/rust/util/rust-attribute-values.h index 9ef5cc5..47e6a17 100644 --- a/gcc/rust/util/rust-attribute-values.h +++ b/gcc/rust/util/rust-attribute-values.h @@ -40,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)] @@ -54,10 +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 03452c7..c77e99c 100644 --- a/gcc/rust/util/rust-attributes.cc +++ b/gcc/rust/util/rust-attributes.cc @@ -57,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}, @@ -72,10 +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::PRELUDE_IMPORT, NAME_RESOLUTION}}; + {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 c928c8e..7c7a1fc 100644 --- a/gcc/rust/util/rust-attributes.h +++ b/gcc/rust/util/rust-attributes.h @@ -40,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-lang-item.cc b/gcc/rust/util/rust-lang-item.cc index a76cc7f..9aff31b 100644 --- a/gcc/rust/util/rust-lang-item.cc +++ b/gcc/rust/util/rust-lang-item.cc @@ -118,6 +118,7 @@ const BiMap<std::string, LangItem::Kind> Rust::LangItem::lang_items = {{ {"discriminant_kind", Kind::DISCRIMINANT_KIND}, {"discriminant_type", Kind::DISCRIMINANT_TYPE}, + {"manually_drop", Kind::MANUALLY_DROP}, }}; tl::optional<LangItem::Kind> diff --git a/gcc/rust/util/rust-lang-item.h b/gcc/rust/util/rust-lang-item.h index 8f3af36..67a5d9c 100644 --- a/gcc/rust/util/rust-lang-item.h +++ b/gcc/rust/util/rust-lang-item.h @@ -150,6 +150,8 @@ public: DISCRIMINANT_TYPE, DISCRIMINANT_KIND, + + MANUALLY_DROP, }; static const BiMap<std::string, Kind> lang_items; diff --git a/gcc/rust/util/rust-stacked-contexts.h b/gcc/rust/util/rust-stacked-contexts.h index fe0bc8a..b263d75 100644 --- a/gcc/rust/util/rust-stacked-contexts.h +++ b/gcc/rust/util/rust-stacked-contexts.h @@ -71,7 +71,14 @@ public: return last; } - const T &peek () + const T &peek () const + { + rust_assert (!stack.empty ()); + + return stack.back (); + } + + T &peek () { rust_assert (!stack.empty ()); |