diff options
Diffstat (limited to 'gcc/rust/backend/rust-compile-base.cc')
-rw-r--r-- | gcc/rust/backend/rust-compile-base.cc | 68 |
1 files changed, 55 insertions, 13 deletions
diff --git a/gcc/rust/backend/rust-compile-base.cc b/gcc/rust/backend/rust-compile-base.cc index 9f936d2..33e4c26 100644 --- a/gcc/rust/backend/rust-compile-base.cc +++ b/gcc/rust/backend/rust-compile-base.cc @@ -30,12 +30,14 @@ namespace Compile { void HIRCompileBase::setup_attributes_on_fndecl ( - tree fndecl, bool is_main_entry_point, bool has_visibility, + tree fndecl, bool is_main_entry_point, HIR::Visibility &visibility, const HIR::FunctionQualifiers &qualifiers, const AST::AttrVec &attrs) { // if its the main fn or pub visibility mark its as DECL_PUBLIC // please see https://github.com/Rust-GCC/gccrs/pull/137 - if (is_main_entry_point || has_visibility) + bool is_pub + = visibility.get_vis_type () != HIR::Visibility::PublicVisType::NONE; + if (is_main_entry_point || is_pub) { TREE_PUBLIC (fndecl) = 1; } @@ -52,20 +54,60 @@ HIRCompileBase::setup_attributes_on_fndecl ( bool is_inline = attr.get_path ().as_string ().compare ("inline") == 0; if (is_inline) { - DECL_DECLARED_INLINE_P (fndecl) = 1; - - // do we want to force inline regardless of optimisation level? - // https://gcc.gnu.org/onlinedocs/gcc/Inline.html - // - // /* Add attribute "always_inline": */ - // DECL_ATTRIBUTES (fndecl) - // = tree_cons (get_identifier ("always_inline"), NULL, - // DECL_ATTRIBUTES (fndecl)); + handle_inline_attribute_on_fndecl (fndecl, attr); } } } void +HIRCompileBase::handle_inline_attribute_on_fndecl (tree fndecl, + const AST::Attribute &attr) +{ + // simple #[inline] + if (!attr.has_attr_input ()) + { + DECL_DECLARED_INLINE_P (fndecl) = 1; + return; + } + + const AST::AttrInput &input = attr.get_attr_input (); + bool is_token_tree + = input.get_attr_input_type () == AST::AttrInput::AttrInputType::TOKEN_TREE; + rust_assert (is_token_tree); + const auto &option = static_cast<const AST::DelimTokenTree &> (input); + AST::AttrInputMetaItemContainer *meta_item = option.parse_to_meta_item (); + if (meta_item->get_items ().size () != 1) + { + rust_error_at (attr.get_locus (), "invalid number of arguments"); + return; + } + + const std::string inline_option + = meta_item->get_items ().at (0)->as_string (); + + // we only care about NEVER and ALWAYS else its an error + bool is_always = inline_option.compare ("always") == 0; + bool is_never = inline_option.compare ("never") == 0; + + // #[inline(never)] + if (is_never) + { + DECL_UNINLINABLE (fndecl) = 1; + } + // #[inline(always)] + else if (is_always) + { + DECL_DECLARED_INLINE_P (fndecl) = 1; + DECL_ATTRIBUTES (fndecl) = tree_cons (get_identifier ("always_inline"), + NULL, DECL_ATTRIBUTES (fndecl)); + } + else + { + rust_error_at (attr.get_locus (), "unknown inline option"); + } +} + +void HIRCompileBase::setup_abi_options (tree fndecl, ABI abi) { switch (abi) @@ -278,8 +320,8 @@ HIRCompileBase::compile_function ( unsigned int flags = 0; tree fndecl = ctx->get_backend ()->function (compiled_fn_type, ir_symbol_name, asm_name, flags, locus); - setup_attributes_on_fndecl (fndecl, is_main_fn, !visibility.is_error (), - qualifiers, outer_attrs); + setup_attributes_on_fndecl (fndecl, is_main_fn, visibility, qualifiers, + outer_attrs); setup_abi_options (fndecl, fntype->get_abi ()); // insert into the context |