Polly 23.0.0git
clang_wrap.h
Go to the documentation of this file.
1#include <isl-interface/config.h>
2
3#include <memory>
4
5#ifdef HAVE_LLVM_OPTION_ARG_H
6#include <llvm/Option/Arg.h>
7#endif
8#ifdef HAVE_TARGETPARSER_HOST_H
9#include <llvm/TargetParser/Host.h>
10#else
11#include <llvm/Support/Host.h>
12#endif
13#include <clang/AST/ASTContext.h>
14#include <clang/Basic/Builtins.h>
15#include <clang/Basic/DiagnosticOptions.h>
16#include <clang/Basic/FileManager.h>
17#include <clang/Basic/TargetOptions.h>
18#include <clang/Basic/TargetInfo.h>
19#include <clang/Basic/Version.h>
20#include <clang/Driver/Compilation.h>
21#include <clang/Driver/Driver.h>
22#include <clang/Driver/Tool.h>
23#include <clang/Frontend/CompilerInstance.h>
24#include <clang/Frontend/CompilerInvocation.h>
25#include <clang/Frontend/TextDiagnosticPrinter.h>
26#include <clang/Lex/HeaderSearch.h>
27#include <clang/Lex/PreprocessorOptions.h>
28#include <clang/Lex/Preprocessor.h>
29
30namespace clang { namespace driver { class Job; } }
31
32namespace isl {
33namespace clang {
34
35using namespace ::clang;
36using namespace ::clang::driver;
37#ifdef HAVE_LLVM_OPTION_ARG_H
38using namespace llvm::opt;
39#endif
40
41#ifndef ISL_CLANG_RESOURCE_DIR
42#define ISL_CLANG_RESOURCE_DIR \
43 ISL_CLANG_PREFIX "/lib/clang/" CLANG_VERSION_STRING
44#endif
46
47static Driver *construct_driver(const char *binary, DiagnosticsEngine &Diags)
48{
49 return new Driver(binary, llvm::sys::getDefaultTargetTriple(), Diags);
50}
51
52/* Clang changed its API from 3.5 to 3.6 and once more in 3.7.
53 * We fix this with a simple overloaded function here.
54 */
55struct ClangAPI {
56 static Job *command(Job *J) { return J; }
57 static Job *command(Job &J) { return &J; }
58 static Command *command(Command &C) { return &C; }
59};
60
61#ifdef CREATE_FROM_ARGS_TAKES_ARRAYREF
62
63/* Call CompilerInvocation::CreateFromArgs with the right arguments.
64 * In this case, an ArrayRef<const char *>.
65 */
66static void create_from_args(CompilerInvocation &invocation,
67 const ArgStringList *args, DiagnosticsEngine &Diags)
68{
69 CompilerInvocation::CreateFromArgs(invocation, *args, Diags);
70}
71
72#else
73
74/* Call CompilerInvocation::CreateFromArgs with the right arguments.
75 * In this case, two "const char *" pointers.
76 */
77static void create_from_args(CompilerInvocation &invocation,
78 const ArgStringList *args, DiagnosticsEngine &Diags)
79{
80 CompilerInvocation::CreateFromArgs(invocation, args->data() + 1,
81 args->data() + args->size(),
82 Diags);
83}
84
85#endif
86
87#ifdef ISL_CLANG_SYSROOT
88/* Set sysroot if required.
89 *
90 * If ISL_CLANG_SYSROOT is defined, then set it to this value.
91 */
92static void set_sysroot(ArgStringList &args)
93{
94 args.push_back("-isysroot");
95 args.push_back(ISL_CLANG_SYSROOT);
96}
97#else
98/* Set sysroot if required.
99 *
100 * If ISL_CLANG_SYSROOT is not defined, then it does not need to be set.
101 */
102static void set_sysroot(ArgStringList &args)
103{
104}
105#endif
106
107/* Create a CompilerInvocation object that stores the command line
108 * arguments constructed by the driver.
109 * The arguments are mainly useful for setting up the system include
110 * paths on newer clangs and on some platforms.
111 */
112static void construct_invocation(CompilerInstance *Clang,
113 const char *filename, DiagnosticsEngine &Diags)
114{
115 const char *binary = ISL_CLANG_PREFIX"/bin/clang";
116 const std::unique_ptr<Driver> driver(construct_driver(binary, Diags));
117 std::vector<const char *> Argv;
118 Argv.push_back(binary);
119 Argv.push_back(filename);
120 const std::unique_ptr<Compilation> compilation(
121 driver->BuildCompilation(llvm::ArrayRef<const char *>(Argv)));
122 JobList &Jobs = compilation->getJobs();
123
124 Command *cmd = cast<Command>(ClangAPI::command(*Jobs.begin()));
125 if (strcmp(cmd->getCreator().getName(), "clang"))
126 return;
127
128 ArgStringList args = cmd->getArguments();
129 set_sysroot(args);
130
131 create_from_args(Clang->getInvocation(), &args, Diags);
132}
133
134#ifdef CREATETARGETINFO_TAKES_SHARED_PTR
135
136static TargetInfo *create_target_info(CompilerInstance *Clang,
137 DiagnosticsEngine &Diags)
138{
139 std::shared_ptr<TargetOptions> TO = Clang->getInvocation().TargetOpts;
140 TO->Triple = llvm::sys::getDefaultTargetTriple();
141 return TargetInfo::CreateTargetInfo(Diags, TO);
142}
143
144#else
145
146static TargetInfo *create_target_info(CompilerInstance *Clang,
147 DiagnosticsEngine &Diags)
148{
149 TargetOptions &TO = Clang->getTargetOpts();
150 TO.Triple = llvm::sys::getDefaultTargetTriple();
151 return TargetInfo::CreateTargetInfo(Diags, TO);
152}
153
154#endif
155
156#ifdef CREATEDIAGNOSTICS_TAKES_VFS
157
158static void create_diagnostics(CompilerInstance *Clang)
159{
160 Clang->createDiagnostics(*llvm::vfs::getRealFileSystem());
161}
162
163#else
164
165static void create_diagnostics(CompilerInstance *Clang)
166{
167 Clang->createDiagnostics();
168}
169
170#endif
171
172static void create_preprocessor(CompilerInstance *Clang)
173{
174 Clang->createPreprocessor(TU_Complete);
175}
176
177/* Add "Path" to the header search options.
178 *
179 * Do not take into account sysroot, i.e., set ignoreSysRoot to true.
180 */
181static void add_path(HeaderSearchOptions &HSO, std::string Path)
182{
183 HSO.AddPath(Path, frontend::Angled, false, true);
184}
185
186template <typename T>
187static void create_main_file_id(SourceManager &SM, const T &file)
188{
189 SM.setMainFileID(SM.createFileID(file, SourceLocation(),
190 SrcMgr::C_User));
191}
192
193#ifdef SETLANGDEFAULTS_TAKES_5_ARGUMENTS
194
196
197static void set_lang_defaults(CompilerInstance *Clang)
198{
199 PreprocessorOptions &PO = Clang->getPreprocessorOpts();
200 TargetOptions &TO = Clang->getTargetOpts();
201 llvm::Triple T(TO.Triple);
202 SETLANGDEFAULTS::setLangDefaults(Clang->getLangOpts(), IK_C, T,
204 LangStandard::lang_unspecified);
205}
206
207#else
208
209static void set_lang_defaults(CompilerInstance *Clang)
210{
211 CompilerInvocation::setLangDefaults(Clang->getLangOpts(), IK_C,
212 LangStandard::lang_unspecified);
213}
214
215#endif
216
217/* Helper function for ignore_error that only gets enabled if T
218 * (which is either const FileEntry * or llvm::ErrorOr<const FileEntry *>)
219 * has getError method, i.e., if it is llvm::ErrorOr<const FileEntry *>.
220 */
221template <class T>
222static const FileEntry *ignore_error_helper(const T obj, int,
223 int[1][sizeof(obj.getError())])
224{
225 return *obj;
226}
227
228/* Helper function for ignore_error that is always enabled,
229 * but that only gets selected if the variant above is not enabled,
230 * i.e., if T is const FileEntry *.
231 */
232template <class T>
233static const FileEntry *ignore_error_helper(const T obj, long, void *)
234{
235 return obj;
236}
237
238/* Given either a const FileEntry * or a llvm::ErrorOr<const FileEntry *>,
239 * extract out the const FileEntry *.
240 */
241template <class T>
242static const FileEntry *ignore_error(const T obj)
243{
244 return ignore_error_helper(obj, 0, NULL);
245}
246
247/* Define a template class "CLASS" with value true
248 * if "EXPR" is valid for its template argument (available as "U" in "EXPR").
249 */
250#define ISL_VALID_EXPR_FOR_TEMPLATE_ARG(CLASS, EXPR) \
251template <typename T> \
252struct CLASS { \
253private: \
254 template <typename U> \
255 static auto test(int) -> decltype(EXPR, std::true_type()); \
256 \
257 template <typename> \
258 static std::false_type test(...); \
259 \
260public: \
261 using type = decltype(test<T>(0)); \
262 static constexpr bool value = type::value; \
263};
264
265/* A template class with value true if the template argument
266 * has a getFileRef method.
267 */
269 std::declval<U>().getFileRef(std::declval<const std::string &>()))
270
271/* Return a wrapper around the FileEntryRef/FileEntry
272 * corresponding to the given file name. The wrapper evaluates
273 * to false if an error occurs.
274 *
275 * If T (= FileManager) has a getFileRef method, then call that and
276 * return an llvm::Expected<clang::FileEntryRef>.
277 * Otherwise, call getFile and return a FileEntry (pointer) embedded
278 * in an llvm::ErrorOr.
279 */
280template <typename T,
281 typename std::enable_if<HasGetFileRef<T>::value, bool>::type = true>
282static auto getFile(T& obj, const std::string &filename)
283 -> decltype(obj.getFileRef(filename))
284{
285 return obj.getFileRef(filename);
286}
287template <typename T,
288 typename std::enable_if<!HasGetFileRef<T>::value, bool>::type = true>
289static llvm::ErrorOr<const FileEntry *> getFile(T& obj,
290 const std::string &filename)
291{
292 const FileEntry *file = ignore_error(obj.getFile(filename));
293 if (!file)
294 return std::error_code();
295 return file;
296}
297
298/* A template class with value true if the constructor of the template argument
299 * takes a reference to a DiagnosticOptions object.
300 */
301ISL_VALID_EXPR_FOR_TEMPLATE_ARG(TakesDiagnosticOptionsRef,
302 new U(llvm::errs(), std::declval<DiagnosticOptions &>()))
303
304/* Return the type of the DiagnosticOptions argument of the constructor of "T".
305 *
306 * If TakesDiagnosticOptionsRef holds, then this is a reference
307 * to a DiagnosticOptions object.
308 * Otherwise, it is a pointer to such an object.
309 */
310template <typename T,
311 typename std::enable_if<TakesDiagnosticOptionsRef<T>::value,
312 bool>::type = true>
313static DiagnosticOptions &diag_opts_type();
314template <typename T,
315 typename std::enable_if<!TakesDiagnosticOptionsRef<T>::value,
316 bool>::type = true>
317static DiagnosticOptions *diag_opts_type();
318
319/* A helper class handling the invocation of clang on a file and
320 * allowing a derived class to perform the actual parsing
321 * in an overridden handle() method.
322 * Other virtual methods allow different kinds of configuration.
323 */
324struct Wrap {
325 /* The type of the DiagnosticOptions argument
326 * of the TextDiagnosticPrinter constructor.
327 */
329 /* A local DiagnosticOptions object that is used
330 * if TextDiagnosticPrinter takes a reference
331 * to a DiagnosticOptions object.
332 */
333 DiagnosticOptions DiagOpts;
334
335 /* Return a valid DiagnosticOptions argument
336 * for the constructor of "T".
337 * If "T" takes a reference, then
338 * this is a reference to the DiagOpts field.
339 * Otherwise, it is a pointer to a new object.
340 */
341 template <typename T,
342 typename std::enable_if<TakesDiagnosticOptionsRef<T>::value,
343 bool>::type = true>
344 DiagnosticOptions &getDiagOpts() {
345 return DiagOpts;
346 }
347 template <typename T,
348 typename std::enable_if<!TakesDiagnosticOptionsRef<T>::value,
349 bool>::type = true>
350 DiagnosticOptions *getDiagOpts() {
351 return new DiagnosticOptions();
352 }
353
354 /* Return a valid DiagnosticOptions argument for
355 * the TextDiagnosticPrinter constructor.
356 * If TextDiagnosticPrinter takes a reference, then
357 * this is a reference to the DiagOpts field.
358 * Otherwise, it is a pointer to a new object.
359 */
363
364 /* Construct a TextDiagnosticPrinter. */
365 virtual TextDiagnosticPrinter *construct_printer() = 0;
366 /* Suppress any errors, if needed. */
367 virtual void suppress_errors(DiagnosticsEngine &Diags) = 0;
368 /* Add required search paths to "HSO". */
369 virtual void add_paths(HeaderSearchOptions &HSO) = 0;
370 /* Add required macro definitions to "PO". */
371 virtual void add_macros(PreprocessorOptions &PO) = 0;
372 /* Handle an error opening the file. */
373 virtual void handle_error() = 0;
374 /* Parse the file, returning true if no error was encountered. */
375 virtual bool handle(CompilerInstance *Clang) = 0;
376
377 /* Invoke clang on "filename", passing control to the handle() method
378 * for parsing.
379 */
380 bool invoke(const char *filename) {
381 CompilerInstance *Clang = new CompilerInstance();
382 create_diagnostics(Clang);
383 DiagnosticsEngine &Diags = Clang->getDiagnostics();
384 Diags.setSuppressSystemWarnings(true);
385 suppress_errors(Diags);
386 TargetInfo *target = create_target_info(Clang, Diags);
387 Clang->setTarget(target);
388 set_lang_defaults(Clang);
389 construct_invocation(Clang, filename, Diags);
390 Diags.setClient(construct_printer());
391 Clang->createFileManager();
392 Clang->createSourceManager(Clang->getFileManager());
393 HeaderSearchOptions &HSO = Clang->getHeaderSearchOpts();
394 LangOptions &LO = Clang->getLangOpts();
395 PreprocessorOptions &PO = Clang->getPreprocessorOpts();
396 HSO.ResourceDir = ResourceDir;
397 HSO.AddPath(ISL_CLANG_RESOURCE_DIR "/include",
398 clang::frontend::System, false, false);
399
400 add_paths(HSO);
401 add_macros(PO);
402
403 create_preprocessor(Clang);
404 Preprocessor &PP = Clang->getPreprocessor();
405
406 PP.getBuiltinInfo().initializeBuiltins(PP.getIdentifierTable(),
407 LO);
408 auto file = getFile(Clang->getFileManager(), filename);
409 if (!file) {
410 handle_error();
411 delete Clang;
412 return false;
413 }
414 create_main_file_id(Clang->getSourceManager(), *file);
415
416 Clang->createASTContext();
417 bool ok = handle(Clang);
418 delete Clang;
419
420 return ok;
421 }
422};
423
424}
425}
#define ISL_VALID_EXPR_FOR_TEMPLATE_ARG(CLASS, EXPR)
Definition clang_wrap.h:250
#define ISL_CLANG_RESOURCE_DIR
Definition clang_wrap.h:42
#define C(FN,...)
Definition isl_test2.cc:266
enum isl_fold type
Definition isl_test.c:3810
const char * obj
Definition isl_test.c:3109
static DiagnosticOptions * diag_opts_type()
static void construct_invocation(CompilerInstance *Clang, const char *filename, DiagnosticsEngine &Diags)
Definition clang_wrap.h:112
static void create_preprocessor(CompilerInstance *Clang)
Definition clang_wrap.h:172
static const char * ResourceDir
Definition clang_wrap.h:45
static TargetInfo * create_target_info(CompilerInstance *Clang, DiagnosticsEngine &Diags)
Definition clang_wrap.h:146
static void create_diagnostics(CompilerInstance *Clang)
Definition clang_wrap.h:165
static void set_lang_defaults(CompilerInstance *Clang)
Definition clang_wrap.h:209
static void create_from_args(CompilerInvocation &invocation, const ArgStringList *args, DiagnosticsEngine &Diags)
Definition clang_wrap.h:77
static void create_main_file_id(SourceManager &SM, const T &file)
Definition clang_wrap.h:187
static void set_sysroot(ArgStringList &args)
Definition clang_wrap.h:102
static Driver * construct_driver(const char *binary, DiagnosticsEngine &Diags)
Definition clang_wrap.h:47
static const FileEntry * ignore_error_helper(const T obj, int, int[1][sizeof(obj.getError())])
Definition clang_wrap.h:222
static const FileEntry * ignore_error(const T obj)
Definition clang_wrap.h:242
static void add_path(HeaderSearchOptions &HSO, std::string Path)
Definition clang_wrap.h:181
These are automatically generated conversions between the default and the checked C++ bindings for is...
Definition ISLTools.h:45
static Command * command(Command &C)
Definition clang_wrap.h:58
static Job * command(Job &J)
Definition clang_wrap.h:57
static Job * command(Job *J)
Definition clang_wrap.h:56
DiagnosticOptions & getDiagOpts()
Definition clang_wrap.h:344
virtual void suppress_errors(DiagnosticsEngine &Diags)=0
virtual bool handle(CompilerInstance *Clang)=0
virtual void add_macros(PreprocessorOptions &PO)=0
DiagOptsType getDiagnosticOptions()
Definition clang_wrap.h:360
bool invoke(const char *filename)
Definition clang_wrap.h:380
virtual void add_paths(HeaderSearchOptions &HSO)=0
virtual TextDiagnosticPrinter * construct_printer()=0
DiagnosticOptions DiagOpts
Definition clang_wrap.h:333
virtual void handle_error()=0
decltype(diag_opts_type< TextDiagnosticPrinter >()) DiagOptsType
Definition clang_wrap.h:328
DiagnosticOptions * getDiagOpts()
Definition clang_wrap.h:350