aboutsummaryrefslogtreecommitdiff
path: root/gcc/rust
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/rust')
-rw-r--r--gcc/rust/ChangeLog353
-rw-r--r--gcc/rust/ast/rust-ast-collector.cc45
-rw-r--r--gcc/rust/ast/rust-ast-collector.h1
-rw-r--r--gcc/rust/ast/rust-ast-visitor.cc30
-rw-r--r--gcc/rust/ast/rust-ast-visitor.h4
-rw-r--r--gcc/rust/ast/rust-ast.cc6
-rw-r--r--gcc/rust/ast/rust-ast.h19
-rw-r--r--gcc/rust/ast/rust-expr.h93
-rw-r--r--gcc/rust/ast/rust-path.cc2
-rw-r--r--gcc/rust/ast/rust-path.h28
-rw-r--r--gcc/rust/backend/rust-compile-asm.cc54
-rw-r--r--gcc/rust/backend/rust-compile-asm.h14
-rw-r--r--gcc/rust/backend/rust-compile-block.h2
-rw-r--r--gcc/rust/backend/rust-compile-expr.cc11
-rw-r--r--gcc/rust/backend/rust-compile-expr.h1
-rw-r--r--gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.cc4
-rw-r--r--gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.h1
-rw-r--r--gcc/rust/checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h1
-rw-r--r--gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h1
-rw-r--r--gcc/rust/checks/errors/borrowck/rust-bir-place.h12
-rw-r--r--gcc/rust/checks/errors/borrowck/rust-bir.h40
-rw-r--r--gcc/rust/checks/errors/borrowck/rust-function-collector.h1
-rw-r--r--gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc4
-rw-r--r--gcc/rust/checks/errors/privacy/rust-privacy-reporter.h1
-rw-r--r--gcc/rust/checks/errors/rust-const-checker.cc4
-rw-r--r--gcc/rust/checks/errors/rust-const-checker.h1
-rw-r--r--gcc/rust/checks/errors/rust-hir-pattern-analysis.cc4
-rw-r--r--gcc/rust/checks/errors/rust-hir-pattern-analysis.h1
-rw-r--r--gcc/rust/checks/errors/rust-unsafe-checker.cc16
-rw-r--r--gcc/rust/checks/errors/rust-unsafe-checker.h1
-rw-r--r--gcc/rust/expand/rust-derive-clone.cc8
-rw-r--r--gcc/rust/expand/rust-derive.h1
-rw-r--r--gcc/rust/expand/rust-expand-visitor.cc3
-rw-r--r--gcc/rust/expand/rust-macro-builtins-asm.cc237
-rw-r--r--gcc/rust/expand/rust-macro-builtins-asm.h32
-rw-r--r--gcc/rust/expand/rust-macro-builtins.cc11
-rw-r--r--gcc/rust/expand/rust-macro-builtins.h4
-rw-r--r--gcc/rust/hir/rust-ast-lower-base.cc4
-rw-r--r--gcc/rust/hir/rust-ast-lower-base.h1
-rw-r--r--gcc/rust/hir/rust-ast-lower-expr.cc44
-rw-r--r--gcc/rust/hir/rust-ast-lower-expr.h1
-rw-r--r--gcc/rust/hir/rust-ast-lower-type.cc2
-rw-r--r--gcc/rust/hir/rust-hir-dump.cc8
-rw-r--r--gcc/rust/hir/rust-hir-dump.h1
-rw-r--r--gcc/rust/hir/tree/rust-hir-expr-abstract.h1
-rw-r--r--gcc/rust/hir/tree/rust-hir-expr.h74
-rw-r--r--gcc/rust/hir/tree/rust-hir-full-decls.h1
-rw-r--r--gcc/rust/hir/tree/rust-hir-item.h2
-rw-r--r--gcc/rust/hir/tree/rust-hir-visitor.h3
-rw-r--r--gcc/rust/hir/tree/rust-hir.cc11
-rw-r--r--gcc/rust/parse/rust-parse-impl.h36
-rw-r--r--gcc/rust/parse/rust-parse.h2
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-base.cc4
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-base.h1
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-expr.cc11
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-expr.h1
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-path.cc8
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-type.cc3
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-type.h4
-rw-r--r--gcc/rust/resolve/rust-default-resolver.cc8
-rw-r--r--gcc/rust/resolve/rust-default-resolver.h2
-rw-r--r--gcc/rust/resolve/rust-early-name-resolver-2.0.cc9
-rw-r--r--gcc/rust/resolve/rust-early-name-resolver-2.0.h16
-rw-r--r--gcc/rust/resolve/rust-forever-stack.h24
-rw-r--r--gcc/rust/resolve/rust-forever-stack.hxx44
-rw-r--r--gcc/rust/resolve/rust-late-name-resolver-2.0.cc153
-rw-r--r--gcc/rust/resolve/rust-late-name-resolver-2.0.h8
-rw-r--r--gcc/rust/resolve/rust-name-resolution-context.cc59
-rw-r--r--gcc/rust/resolve/rust-name-resolution-context.h145
-rw-r--r--gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc5
-rw-r--r--gcc/rust/rust-gcc.cc1
-rw-r--r--gcc/rust/typecheck/rust-hir-trait-resolve.cc21
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-base.cc44
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-expr.cc31
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-expr.h1
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-item.cc44
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-struct-field.h3
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-struct.cc54
-rw-r--r--gcc/rust/typecheck/rust-tyty.cc85
-rw-r--r--gcc/rust/typecheck/rust-tyty.h19
-rw-r--r--gcc/rust/util/rust-stacked-contexts.h9
81 files changed, 1873 insertions, 186 deletions
diff --git a/gcc/rust/ChangeLog b/gcc/rust/ChangeLog
index 453b9f7..5cb9311 100644
--- a/gcc/rust/ChangeLog
+++ b/gcc/rust/ChangeLog
@@ -1,3 +1,356 @@
+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.
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 &param)
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 &param);
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 &param)
{
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 &param : 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 &param : 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 &param) = 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 &param) 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 91611ec..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;
@@ -1264,6 +1269,7 @@ public:
Await,
AsyncBlock,
InlineAsm,
+ LlvmInlineAsm,
Identifier,
FormatArgs,
MacroInvocation,
@@ -2096,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 69538df..fdb6360 100644
--- a/gcc/rust/ast/rust-expr.h
+++ b/gcc/rust/ast/rust-expr.h
@@ -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 &param) override { rust_unreachable (); }
void visit (HIR::ConstGenericParam &param) 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-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 &param) override {}
void visit (HIR::ConstGenericParam &param) 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 4c2257a..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 &)
{}
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 &param) override;
virtual void visit (ConstGenericParam &param) 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 &param) override;
virtual void visit (ConstGenericParam &param) 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 &param) override;
virtual void visit (ConstGenericParam &param) 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 &param) 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.cc b/gcc/rust/expand/rust-macro-builtins.cc
index 8b406ff..b58ed71 100644
--- a/gcc/rust/expand/rust-macro-builtins.cc
+++ b/gcc/rust/expand/rust-macro-builtins.cc
@@ -103,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},
@@ -121,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 */
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/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 &param)
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 &param) = 0;
virtual void visit (ConstGenericParam &param) = 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-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 &param) 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 &param)
+{
+ auto expr_vis = [this, &param] () { 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 36456e1..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 ()));
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 &param : 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 &param : 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 &param : 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 ba37dee..2f036fe 100644
--- a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc
+++ b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc
@@ -135,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);
}
@@ -548,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 234721c..e5319d3 100644
--- a/gcc/rust/rust-gcc.cc
+++ b/gcc/rust/rust-gcc.cc
@@ -1109,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");
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 b2bcac0..cbf529a 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-expr.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-expr.cc
@@ -844,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;
@@ -1129,27 +1142,25 @@ 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;
}
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 &param : 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 &param : 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-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 ());