aboutsummaryrefslogtreecommitdiff
path: root/gcc/rust/expand
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/rust/expand')
-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
7 files changed, 293 insertions, 3 deletions
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);