This commit adds a base for creating AST FormatArgs nodes after expanding invocations of `format_args!()`. These nodes will then be expanded to the proper runtime function calls (to core::fmt::rt) during the AST lowering.
gcc/rust/ChangeLog: * ast/rust-builtin-ast-nodes.h: New file. * ast/rust-ast-full-decls.h (class FormatArgs): Declare new class. * ast/rust-ast-collector.cc: Handle FormatArgs nodes properly. * ast/rust-ast-collector.h: Likewise. * ast/rust-ast-full.h: Likewise. * ast/rust-ast-visitor.cc: Likewise. * ast/rust-ast-visitor.h: Likewise. * ast/rust-ast.cc: Likewise. * ast/rust-ast.h: Likewise. * expand/rust-derive.h: Likewise. * hir/rust-ast-lower-base.cc: Likewise. * hir/rust-ast-lower-base.h: Likewise. * hir/rust-ast-lower-expr.cc: Likewise. * hir/rust-ast-lower-expr.h: Likewise. * resolve/rust-ast-resolve-base.cc: Likewise. * resolve/rust-ast-resolve-base.h: Likewise. --- gcc/rust/ast/rust-ast-collector.cc | 8 ++ gcc/rust/ast/rust-ast-collector.h | 2 + gcc/rust/ast/rust-ast-full-decls.h | 3 + gcc/rust/ast/rust-ast-full.h | 1 + gcc/rust/ast/rust-ast-visitor.cc | 6 + gcc/rust/ast/rust-ast-visitor.h | 5 + gcc/rust/ast/rust-ast.cc | 6 + gcc/rust/ast/rust-ast.h | 1 + gcc/rust/ast/rust-builtin-ast-nodes.h | 129 ++++++++++++++++++++++ gcc/rust/expand/rust-derive.h | 1 + gcc/rust/hir/rust-ast-lower-base.cc | 5 + gcc/rust/hir/rust-ast-lower-base.h | 3 + gcc/rust/hir/rust-ast-lower-expr.cc | 8 ++ gcc/rust/hir/rust-ast-lower-expr.h | 4 + gcc/rust/resolve/rust-ast-resolve-base.cc | 6 + gcc/rust/resolve/rust-ast-resolve-base.h | 3 + 16 files changed, 191 insertions(+) create mode 100644 gcc/rust/ast/rust-builtin-ast-nodes.h diff --git a/gcc/rust/ast/rust-ast-collector.cc b/gcc/rust/ast/rust-ast-collector.cc index 181f1b100be..b8ec62367bc 100644 --- a/gcc/rust/ast/rust-ast-collector.cc +++ b/gcc/rust/ast/rust-ast-collector.cc @@ -16,6 +16,8 @@ // along with GCC; see the file COPYING3. If not see // <http://www.gnu.org/licenses/>. #include "rust-ast-collector.h" +#include "rust-ast.h" +#include "rust-diagnostics.h" #include "rust-item.h" #include "rust-keyword-values.h" @@ -2805,5 +2807,11 @@ TokenCollector::visit (BareFunctionType &type) } } +void +TokenCollector::visit (AST::FormatArgs &fmt) +{ + rust_sorry_at (0, "unimplemented format_args!() visitor"); +} + } // namespace AST } // namespace Rust diff --git a/gcc/rust/ast/rust-ast-collector.h b/gcc/rust/ast/rust-ast-collector.h index cf97c185a26..ec695ef5b31 100644 --- a/gcc/rust/ast/rust-ast-collector.h +++ b/gcc/rust/ast/rust-ast-collector.h @@ -398,6 +398,8 @@ public: void visit (SliceType &type); void visit (InferredType &type); void visit (BareFunctionType &type); + + void visit (FormatArgs &fmt); }; } // namespace AST diff --git a/gcc/rust/ast/rust-ast-full-decls.h b/gcc/rust/ast/rust-ast-full-decls.h index c96bbfb07d9..8d5c8dbc821 100644 --- a/gcc/rust/ast/rust-ast-full-decls.h +++ b/gcc/rust/ast/rust-ast-full-decls.h @@ -267,6 +267,9 @@ class SliceType; class InferredType; struct MaybeNamedParam; class BareFunctionType; + +// rust-builtin-ast-nodes.h +class FormatArgs; } // namespace AST } // namespace Rust diff --git a/gcc/rust/ast/rust-ast-full.h b/gcc/rust/ast/rust-ast-full.h index f2152193a13..ebd38f2520c 100644 --- a/gcc/rust/ast/rust-ast-full.h +++ b/gcc/rust/ast/rust-ast-full.h @@ -28,5 +28,6 @@ #include "rust-stmt.h" #include "rust-type.h" #include "rust-macro.h" +#include "rust-builtin-ast-nodes.h" #endif diff --git a/gcc/rust/ast/rust-ast-visitor.cc b/gcc/rust/ast/rust-ast-visitor.cc index 27b9aa47d99..c72e2d72f6d 100644 --- a/gcc/rust/ast/rust-ast-visitor.cc +++ b/gcc/rust/ast/rust-ast-visitor.cc @@ -1395,6 +1395,12 @@ DefaultASTVisitor::visit (AST::BareFunctionType &type) visit (type.get_return_type ()); } +void +DefaultASTVisitor::visit (AST::FormatArgs &) +{ + // FIXME: Do we have anything to do? any subnodes to visit? Probably, right? +} + void DefaultASTVisitor::visit (AST::VariadicParam ¶m) { diff --git a/gcc/rust/ast/rust-ast-visitor.h b/gcc/rust/ast/rust-ast-visitor.h index 6c9715eb077..c5c9a025ba6 100644 --- a/gcc/rust/ast/rust-ast-visitor.h +++ b/gcc/rust/ast/rust-ast-visitor.h @@ -229,6 +229,9 @@ public: virtual void visit (InferredType &type) = 0; virtual void visit (BareFunctionType &type) = 0; + // special AST nodes for certain builtin macros such as `asm!()` + virtual void visit (FormatArgs &fmt) = 0; + // TODO: rust-cond-compilation.h visiting? not currently used }; @@ -390,6 +393,7 @@ protected: virtual void visit (AST::SelfParam &self) override; virtual void visit (AST::FunctionParam ¶m) override; virtual void visit (AST::VariadicParam ¶m) override; + virtual void visit (AST::FormatArgs &fmt) override; template <typename T> void visit (T &node) { node.accept_vis (*this); } @@ -422,6 +426,7 @@ protected: virtual void visit (AST::MacroTranscriber &transcriber); virtual void visit (AST::StructPatternElements &spe); virtual void visit (AST::MaybeNamedParam ¶m); + void visit (AST::Attribute &attribute) {} template <typename T> void visit_outer_attrs (T &node) diff --git a/gcc/rust/ast/rust-ast.cc b/gcc/rust/ast/rust-ast.cc index 90fe9269404..5d571b46622 100644 --- a/gcc/rust/ast/rust-ast.cc +++ b/gcc/rust/ast/rust-ast.cc @@ -5048,6 +5048,12 @@ MetaWord::accept_vis (ASTVisitor &vis) vis.visit (*this); } +void +FormatArgs::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + } // namespace AST std::ostream & diff --git a/gcc/rust/ast/rust-ast.h b/gcc/rust/ast/rust-ast.h index 1422d77eade..c4d5858dd63 100644 --- a/gcc/rust/ast/rust-ast.h +++ b/gcc/rust/ast/rust-ast.h @@ -2029,6 +2029,7 @@ public: class PathExpr : public ExprWithoutBlock { }; + } // namespace AST } // namespace Rust diff --git a/gcc/rust/ast/rust-builtin-ast-nodes.h b/gcc/rust/ast/rust-builtin-ast-nodes.h new file mode 100644 index 00000000000..3998fbfb4a7 --- /dev/null +++ b/gcc/rust/ast/rust-builtin-ast-nodes.h @@ -0,0 +1,129 @@ +// Copyright (C) 2024 Free Software Foundation, Inc. + +// This file is part of GCC. + +// GCC is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 3, or (at your option) any later +// version. + +// GCC is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. + +// You should have received a copy of the GNU General Public License +// along with GCC; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#ifndef RUST_AST_BUILTIN_NODES_H +#define RUST_AST_BUILTIN_NODES_H + +#include "rust-system.h" +#include "line-map.h" +#include "optional.h" +#include "rust-ast.h" +#include "rust-fmt.h" + +namespace Rust { +namespace AST { + +// Definitions, from rustc's `FormatArgs` AST struct +// https://github.com/rust-lang/rust/blob/1be468815c/compiler/rustc_ast/src/format.rs +// +// format_args!("hello {abc:.xyz$}!!", abc="world"); +// └──────────────────────────────────────────────┘ +// FormatArgs +// +// format_args!("hello {abc:.xyz$}!!", abc="world"); +// └─────────┘ +// argument +// +// format_args!("hello {abc:.xyz$}!!", abc="world"); +// └───────────────────┘ +// template +// +// format_args!("hello {abc:.xyz$}!!", abc="world"); +// └────┘└─────────┘└┘ +// pieces +// +// format_args!("hello {abc:.xyz$}!!", abc="world"); +// └────┘ └┘ +// literal pieces +// +// format_args!("hello {abc:.xyz$}!!", abc="world"); +// └─────────┘ +// placeholder +// +// format_args!("hello {abc:.xyz$}!!", abc="world"); +// └─┘ └─┘ +// positions (could be names, numbers, empty, or `*`) + +class FormatArgumentKind +{ +public: + Identifier &get_ident () + { + rust_assert (kind == Kind::Captured || kind == Kind::Named); + + return ident.value (); + } + +private: + enum class Kind + { + Normal, + Named, + Captured, + } kind; + + tl::optional<Identifier> ident; +}; + +class FormatArgument +{ + FormatArgumentKind kind; + std::unique_ptr<Expr> expr; +}; + +class FormatArguments +{ + std::vector<FormatArgument> args; +}; + +// TODO: Format documentation better +// Having a separate AST node for `format_args!()` expansion allows some +// important optimizations which help reduce generated code a lot. For example, +// turning `format_args!("a {} {} {}", 15, "hey", 'a')` directly into +// `format_args!("a 15 hey a")`, since all arguments are literals. Or, +// flattening imbricated `format_args!()` calls: `format_args!("heyo {}", +// format_args!("result: {}", some_result))` -> `format_args!("heyo result: {}", +// some_result)` +// FIXME: Move to rust-macro.h +class FormatArgs : public Visitable +{ +public: + enum class Newline + { + Yes, + No + }; + + FormatArgs (location_t loc, Fmt::PieceSlice template_str, + FormatArguments arguments) + : loc (loc), template_str (std::move (template_str)), + arguments (std::move (arguments)) + {} + + void accept_vis (AST::ASTVisitor &vis); + +private: + location_t loc; + Fmt::PieceSlice template_str; + FormatArguments arguments; +}; + +} // namespace AST +} // namespace Rust + +#endif // ! RUST_AST_BUILTIN_NODES_H diff --git a/gcc/rust/expand/rust-derive.h b/gcc/rust/expand/rust-derive.h index 8fe29c0db75..f953c3decbf 100644 --- a/gcc/rust/expand/rust-derive.h +++ b/gcc/rust/expand/rust-derive.h @@ -221,6 +221,7 @@ private: virtual void visit (SelfParam ¶m) override final{}; virtual void visit (FunctionParam ¶m) override final{}; virtual void visit (VariadicParam ¶m) override final{}; + virtual void visit (FormatArgs ¶m) override final{}; }; } // namespace AST diff --git a/gcc/rust/hir/rust-ast-lower-base.cc b/gcc/rust/hir/rust-ast-lower-base.cc index bcc4797df77..fa37d62d026 100644 --- a/gcc/rust/hir/rust-ast-lower-base.cc +++ b/gcc/rust/hir/rust-ast-lower-base.cc @@ -20,6 +20,7 @@ #include "rust-ast-lower-type.h" #include "rust-ast-lower-pattern.h" #include "rust-ast-lower-extern.h" +#include "rust-ast.h" #include "rust-attribute-values.h" #include "rust-item.h" #include "rust-system.h" @@ -523,6 +524,10 @@ void ASTLoweringBase::visit (AST::SelfParam ¶m) {} +void +ASTLoweringBase::visit (AST::FormatArgs &fmt) +{} + HIR::Lifetime ASTLoweringBase::lower_lifetime (AST::Lifetime &lifetime, bool default_to_static_lifetime) diff --git a/gcc/rust/hir/rust-ast-lower-base.h b/gcc/rust/hir/rust-ast-lower-base.h index d7b94ac8a70..7b0ce375f83 100644 --- a/gcc/rust/hir/rust-ast-lower-base.h +++ b/gcc/rust/hir/rust-ast-lower-base.h @@ -19,6 +19,7 @@ #ifndef RUST_AST_LOWER_BASE #define RUST_AST_LOWER_BASE +#include "rust-ast.h" #include "rust-system.h" #include "rust-ast-full.h" #include "rust-ast-visitor.h" @@ -253,6 +254,8 @@ public: virtual void visit (AST::VariadicParam ¶m); virtual void visit (AST::SelfParam ¶m); + virtual void visit (AST::FormatArgs &fmt); + protected: ASTLoweringBase () : mappings (Analysis::Mappings::get ()), diff --git a/gcc/rust/hir/rust-ast-lower-expr.cc b/gcc/rust/hir/rust-ast-lower-expr.cc index 35deb57abe6..8e07b19df4c 100644 --- a/gcc/rust/hir/rust-ast-lower-expr.cc +++ b/gcc/rust/hir/rust-ast-lower-expr.cc @@ -22,6 +22,8 @@ #include "rust-ast-lower-struct-field-expr.h" #include "rust-ast-lower-pattern.h" #include "rust-ast-lower-type.h" +#include "rust-ast.h" +#include "rust-diagnostics.h" namespace Rust { namespace HIR { @@ -828,5 +830,11 @@ ASTLoweringExpr::visit (AST::ClosureExprInnerTyped &expr) expr.get_locus ()); } +void +ASTLoweringExpr::visit (AST::FormatArgs &fmt) +{ + rust_sorry_at (0, "unimplemented format_args!() visitor"); +} + } // namespace HIR } // namespace Rust diff --git a/gcc/rust/hir/rust-ast-lower-expr.h b/gcc/rust/hir/rust-ast-lower-expr.h index 56da9d1ab88..168dd014002 100644 --- a/gcc/rust/hir/rust-ast-lower-expr.h +++ b/gcc/rust/hir/rust-ast-lower-expr.h @@ -20,6 +20,7 @@ #define RUST_AST_LOWER_EXPR #include "rust-ast-lower-base.h" +#include "rust-ast.h" namespace Rust { namespace HIR { @@ -121,6 +122,9 @@ public: void visit (AST::ClosureExprInner &expr) override; void visit (AST::ClosureExprInnerTyped &expr) override; + // Extra visitor for FormatArgs nodes + void visit (AST::FormatArgs &fmt) override; + private: ASTLoweringExpr (); diff --git a/gcc/rust/resolve/rust-ast-resolve-base.cc b/gcc/rust/resolve/rust-ast-resolve-base.cc index c88bd58860a..04a0bb65ec2 100644 --- a/gcc/rust/resolve/rust-ast-resolve-base.cc +++ b/gcc/rust/resolve/rust-ast-resolve-base.cc @@ -650,5 +650,11 @@ void ResolverBase::visit (AST::FunctionParam &) {} +void +ResolverBase::visit (AST::FormatArgs &fmt) +{ + rust_sorry_at (0, "unimplemented format_args!() visitor"); +} + } // namespace Resolver } // namespace Rust diff --git a/gcc/rust/resolve/rust-ast-resolve-base.h b/gcc/rust/resolve/rust-ast-resolve-base.h index 9bc64331f5a..3b4d28618e4 100644 --- a/gcc/rust/resolve/rust-ast-resolve-base.h +++ b/gcc/rust/resolve/rust-ast-resolve-base.h @@ -20,6 +20,7 @@ #define RUST_AST_RESOLVE_BASE_H #include "rust-ast-visitor.h" +#include "rust-ast.h" #include "rust-name-resolver.h" #include "rust-diagnostics.h" #include "rust-location.h" @@ -198,6 +199,8 @@ public: void visit (AST::VariadicParam ¶m); void visit (AST::SelfParam ¶m); + void visit (AST::FormatArgs &fmt); + protected: ResolverBase () : resolver (Resolver::get ()), mappings (Analysis::Mappings::get ()), -- 2.45.2