]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/rust/expand/rust-proc-macro.cc
gccrs: proc_macro: Rename from_string callback symbol
[thirdparty/gcc.git] / gcc / rust / expand / rust-proc-macro.cc
1 // This file is part of GCC.
2
3 // GCC is free software; you can redistribute it and/or modify it under
4 // the terms of the GNU General Public License as published by the Free
5 // Software Foundation; either version 3, or (at your option) any later
6 // version.
7
8 // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
9 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
11 // for more details.
12
13 // You should have received a copy of the GNU General Public License
14 // along with GCC; see the file COPYING3. If not see
15 // <http://www.gnu.org/licenses/>.
16
17 #include "rust-diagnostics.h"
18 #include "rust-proc-macro.h"
19 #include "rust-lex.h"
20 #include "rust-token-converter.h"
21 #ifndef _WIN32
22 #include <dlfcn.h>
23 #endif
24
25 namespace Rust {
26
27 const std::string PROC_MACRO_DECL_PREFIX = "__gccrs_proc_macro_decls_";
28
29 static ProcMacro::TokenStream
30 tokenstream_from_string (std::string &data, bool &lex_error)
31 {
32 // FIXME: Insert location pointing to call site in tokens
33 Lexer lex (data);
34
35 std::vector<const_TokenPtr> tokens;
36 TokenPtr ptr;
37 for (ptr = lex.build_token ();
38 ptr != nullptr && ptr->get_id () != END_OF_FILE;
39 ptr = lex.build_token ())
40 {
41 tokens.emplace_back (ptr);
42 }
43
44 if (ptr == nullptr)
45 {
46 lex_error = true;
47 return ProcMacro::TokenStream::make_tokenstream ();
48 }
49
50 lex_error = false;
51 return convert (tokens);
52 }
53
54 static_assert (
55 std::is_same<decltype (tokenstream_from_string) *,
56 ProcMacro::from_str_function_t>::value,
57 "Registration callback signature not synced, check proc macro internals.");
58
59 template <typename Symbol, typename Callback>
60 bool
61 register_callback (void *handle, Symbol, std::string symbol_name,
62 Callback callback)
63 {
64 void *addr = dlsym (handle, symbol_name.c_str ());
65 if (addr == nullptr)
66 {
67 rust_error_at (Location (),
68 "Callback registration symbol (%s) missing from "
69 "proc macro, wrong version?",
70 symbol_name.c_str ());
71 return false;
72 }
73
74 auto storage = reinterpret_cast<Symbol *> (addr);
75 *storage = callback;
76
77 return true;
78 }
79
80 #define REGISTER_CALLBACK(HANDLE, SYMBOL, CALLBACK) \
81 register_callback (HANDLE, SYMBOL, #SYMBOL, CALLBACK)
82
83 const ProcMacro::ProcmacroArray *
84 load_macros_array (std::string path)
85 {
86 #ifndef _WIN32
87 void *handle = dlopen (path.c_str (), RTLD_LAZY | RTLD_LOCAL);
88 // We're leaking the handle since we can't ever unload it
89 if (!handle)
90 {
91 rust_debug ("Error whilst opening procedural macro: %s", dlerror ());
92 return nullptr;
93 }
94
95 if (!REGISTER_CALLBACK (handle, __gccrs_proc_macro_from_str_fn,
96 tokenstream_from_string))
97 return nullptr;
98
99 // FIXME: Add CrateStableId handling, right now all versions may be loaded,
100 // even incompatible ones.
101 return *reinterpret_cast<const ProcMacro::ProcmacroArray **> (
102 dlsym (handle, PROC_MACRO_DECL_PREFIX.c_str ()));
103 #else
104 rust_sorry_at (UNDEF_LOCATION,
105 "Procedural macros are not yet supported on windows host");
106 rust_unreachable ();
107 #endif
108 }
109
110 #undef REGISTER_CALLBACK
111
112 const std::vector<ProcMacro::Procmacro>
113 load_macros (std::string path)
114 {
115 const ProcMacro::ProcmacroArray *array = load_macros_array (path);
116 // Did not load the proc macro
117 if (array == nullptr)
118 return {};
119
120 rust_debug ("Found %lu procedural macros", array->length);
121
122 return std::vector<ProcMacro::Procmacro> (array->macros,
123 array->macros + array->length);
124 }
125
126 } // namespace Rust