]> git.ipfire.org Git - thirdparty/gcc.git/blob - c++tools/resolver.cc
Move more code to new gimple-ssa-warn-access pass.
[thirdparty/gcc.git] / c++tools / resolver.cc
1 /* C++ modules. Experimental! -*- c++ -*-
2 Copyright (C) 2017-2021 Free Software Foundation, Inc.
3 Written by Nathan Sidwell <nathan@acm.org> while at FaceBook
4
5 This file is part of GCC.
6
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
11
12 GCC is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
20
21 #include "config.h"
22
23 #include "resolver.h"
24 // C++
25 #include <algorithm>
26 // C
27 #include <cstring>
28 // OS
29 #include <fcntl.h>
30 #include <unistd.h>
31 #if 0 // 1 for testing no mmap
32 #define MAPPED_READING 0
33 #else
34 #ifdef IN_GCC
35 #if HAVE_MMAP_FILE && _POSIX_MAPPED_FILES > 0
36 #define MAPPED_READING 1
37 #else
38 #define MAPPED_READING 0
39 #endif
40 #else
41 #ifdef HAVE_SYS_MMAN_H
42 #include <sys/mman.h>
43 #define MAPPED_READING 1
44 #else
45 #define MAPPED_READING 0
46 #endif
47 #endif
48 #endif
49
50 #include <sys/types.h>
51 #include <sys/stat.h>
52
53 #if !defined (IN_GCC) && !MAPPED_READING
54 #define xmalloc(X) malloc(X)
55 #endif
56
57 #if !HOST_HAS_O_CLOEXEC
58 #define O_CLOEXEC 0
59 #endif
60
61 #ifndef DIR_SEPARATOR
62 #define DIR_SEPARATOR '/'
63 #endif
64
65 module_resolver::module_resolver (bool map, bool xlate)
66 : default_map (map), default_translate (xlate)
67 {
68 }
69
70 module_resolver::~module_resolver ()
71 {
72 if (fd_repo >= 0)
73 close (fd_repo);
74 }
75
76 bool
77 module_resolver::set_repo (std::string &&r, bool force)
78 {
79 if (force || repo.empty ())
80 {
81 repo = std::move (r);
82 force = true;
83 }
84 return force;
85 }
86
87 bool
88 module_resolver::add_mapping (std::string &&module, std::string &&file,
89 bool force)
90 {
91 auto res = map.emplace (std::move (module), std::move (file));
92 if (res.second)
93 force = true;
94 else if (force)
95 res.first->second = std::move (file);
96
97 return force;
98 }
99
100 int
101 module_resolver::read_tuple_file (int fd, char const *prefix, bool force)
102 {
103 struct stat stat;
104 if (fstat (fd, &stat) < 0)
105 return -errno;
106
107 if (!stat.st_size)
108 return 0;
109
110 void *buffer = nullptr;
111 #if MAPPED_READING
112 // Just map the file, we're gonna read all of it, so no need for
113 // line buffering
114 buffer = mmap (nullptr, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
115 if (buffer == MAP_FAILED)
116 return -errno;
117 #else
118 buffer = xmalloc (stat.st_size);
119 if (!buffer)
120 return -errno;
121 if (read (fd, buffer, stat.st_size) != stat.st_size)
122 return -errno;
123 #endif
124
125 size_t prefix_len = prefix ? strlen (prefix) : 0;
126 unsigned lineno = 0;
127
128 for (char const *begin = reinterpret_cast <char const *> (buffer),
129 *end = begin + stat.st_size, *eol;
130 begin != end; begin = eol + 1)
131 {
132 lineno++;
133 eol = std::find (begin, end, '\n');
134 if (eol == end)
135 // last line has no \n, ignore the line, you lose
136 break;
137
138 auto *pos = begin;
139 bool pfx_search = prefix_len != 0;
140
141 pfx_search:
142 while (*pos == ' ' || *pos == '\t')
143 pos++;
144
145 auto *space = pos;
146 while (*space != '\n' && *space != ' ' && *space != '\t')
147 space++;
148
149 if (pos == space)
150 // at end of line, nothing here
151 continue;
152
153 if (pfx_search)
154 {
155 if (size_t (space - pos) == prefix_len
156 && std::equal (pos, space, prefix))
157 pfx_search = false;
158 pos = space;
159 goto pfx_search;
160 }
161
162 std::string module (pos, space);
163 while (*space == ' ' || *space == '\t')
164 space++;
165 std::string file (space, eol);
166
167 if (module[0] == '$')
168 {
169 if (module == "$root")
170 set_repo (std::move (file));
171 else
172 return lineno;
173 }
174 else
175 {
176 if (file.empty ())
177 file = GetCMIName (module);
178 add_mapping (std::move (module), std::move (file), force);
179 }
180 }
181
182 #if MAPPED_READING
183 munmap (buffer, stat.st_size);
184 #else
185 free (buffer);
186 #endif
187
188 return 0;
189 }
190
191 char const *
192 module_resolver::GetCMISuffix ()
193 {
194 return "gcm";
195 }
196
197 module_resolver *
198 module_resolver::ConnectRequest (Cody::Server *s, unsigned version,
199 std::string &a, std::string &i)
200 {
201 if (!version || version > Cody::Version)
202 s->ErrorResponse ("version mismatch");
203 else if (a != "GCC")
204 // Refuse anything but GCC
205 ErrorResponse (s, std::string ("only GCC supported"));
206 else if (!ident.empty () && ident != i)
207 // Failed ident check
208 ErrorResponse (s, std::string ("bad ident"));
209 else
210 // Success!
211 s->ConnectResponse ("gcc");
212
213 return this;
214 }
215
216 int
217 module_resolver::ModuleRepoRequest (Cody::Server *s)
218 {
219 s->PathnameResponse (repo);
220 return 0;
221 }
222
223 int
224 module_resolver::cmi_response (Cody::Server *s, std::string &module)
225 {
226 auto iter = map.find (module);
227 if (iter == map.end ())
228 {
229 std::string file = default_map ? GetCMIName (module) : std::string ();
230 auto res = map.emplace (module, file);
231 iter = res.first;
232 }
233
234 if (iter->second.empty ())
235 s->ErrorResponse ("no such module");
236 else
237 s->PathnameResponse (iter->second);
238
239 return 0;
240 }
241
242 int
243 module_resolver::ModuleExportRequest (Cody::Server *s, Cody::Flags,
244 std::string &module)
245 {
246 return cmi_response (s, module);
247 }
248
249 int
250 module_resolver::ModuleImportRequest (Cody::Server *s, Cody::Flags,
251 std::string &module)
252 {
253 return cmi_response (s, module);
254 }
255
256 int
257 module_resolver::IncludeTranslateRequest (Cody::Server *s, Cody::Flags,
258 std::string &include)
259 {
260 auto iter = map.find (include);
261 if (iter == map.end () && default_translate)
262 {
263 // Not found, look for it
264 auto file = GetCMIName (include);
265 struct stat statbuf;
266 bool ok = true;
267
268 #if HAVE_FSTATAT
269 int fd_dir = AT_FDCWD;
270 if (!repo.empty ())
271 {
272 if (fd_repo == -1)
273 {
274 fd_repo = open (repo.c_str (),
275 O_RDONLY | O_CLOEXEC | O_DIRECTORY);
276 if (fd_repo < 0)
277 fd_repo = -2;
278 }
279 fd_dir = fd_repo;
280 }
281
282 if (!repo.empty () && fd_repo < 0)
283 ok = false;
284 else if (fstatat (fd_dir, file.c_str (), &statbuf, 0) < 0
285 || !S_ISREG (statbuf.st_mode))
286 ok = false;
287 #else
288 auto append = repo;
289 append.push_back (DIR_SEPARATOR);
290 append.append (file);
291 if (stat (append.c_str (), &statbuf) < 0
292 || !S_ISREG (statbuf.st_mode))
293 ok = false;
294 #endif
295 if (!ok)
296 // Mark as not present
297 file.clear ();
298 auto res = map.emplace (include, file);
299 iter = res.first;
300 }
301
302 if (iter == map.end () || iter->second.empty ())
303 s->BoolResponse (false);
304 else
305 s->PathnameResponse (iter->second);
306
307 return 0;
308 }
309