1 /*
2  * Copyright 2011 Sven Verdoolaege. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  *    1. Redistributions of source code must retain the above copyright
9  *       notice, this list of conditions and the following disclaimer.
10  *
11  *    2. Redistributions in binary form must reproduce the above
12  *       copyright notice, this list of conditions and the following
13  *       disclaimer in the documentation and/or other materials provided
14  *       with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY SVEN VERDOOLAEGE ''AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SVEN VERDOOLAEGE OR
20  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
23  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * The views and conclusions contained in the software and documentation
29  * are those of the authors and should not be interpreted as
30  * representing official policies, either expressed or implied, of
31  * Sven Verdoolaege.
32  */
33 
34 #include "isl_config.h"
35 #undef PACKAGE
36 
37 #include <assert.h>
38 #include <iostream>
39 #include <stdlib.h>
40 #ifdef HAVE_ADT_OWNINGPTR_H
41 #include <llvm/ADT/OwningPtr.h>
42 #else
43 #include <memory>
44 #endif
45 #ifdef HAVE_LLVM_OPTION_ARG_H
46 #include <llvm/Option/Arg.h>
47 #endif
48 #include <llvm/Support/raw_ostream.h>
49 #include <llvm/Support/CommandLine.h>
50 #include <llvm/Support/Host.h>
51 #include <llvm/Support/ManagedStatic.h>
52 #include <clang/AST/ASTContext.h>
53 #include <clang/AST/ASTConsumer.h>
54 #include <clang/Basic/Builtins.h>
55 #include <clang/Basic/FileSystemOptions.h>
56 #include <clang/Basic/FileManager.h>
57 #include <clang/Basic/TargetOptions.h>
58 #include <clang/Basic/TargetInfo.h>
59 #include <clang/Basic/Version.h>
60 #include <clang/Driver/Compilation.h>
61 #include <clang/Driver/Driver.h>
62 #include <clang/Driver/Tool.h>
63 #include <clang/Frontend/CompilerInstance.h>
64 #include <clang/Frontend/CompilerInvocation.h>
65 #ifdef HAVE_BASIC_DIAGNOSTICOPTIONS_H
66 #include <clang/Basic/DiagnosticOptions.h>
67 #else
68 #include <clang/Frontend/DiagnosticOptions.h>
69 #endif
70 #include <clang/Frontend/TextDiagnosticPrinter.h>
71 #include <clang/Frontend/Utils.h>
72 #include <clang/Lex/HeaderSearch.h>
73 #ifdef HAVE_LEX_PREPROCESSOROPTIONS_H
74 #include <clang/Lex/PreprocessorOptions.h>
75 #else
76 #include <clang/Frontend/PreprocessorOptions.h>
77 #endif
78 #include <clang/Lex/Preprocessor.h>
79 #include <clang/Parse/ParseAST.h>
80 #include <clang/Sema/Sema.h>
81 
82 #include "extract_interface.h"
83 #include "generator.h"
84 #include "python.h"
85 #include "plain_cpp.h"
86 #include "cpp_conversion.h"
87 #include "template_cpp.h"
88 
89 using namespace std;
90 using namespace clang;
91 using namespace clang::driver;
92 #ifdef HAVE_LLVM_OPTION_ARG_H
93 using namespace llvm::opt;
94 #endif
95 
96 #ifdef HAVE_ADT_OWNINGPTR_H
97 #define unique_ptr	llvm::OwningPtr
98 #endif
99 
100 static llvm::cl::opt<string> InputFilename(llvm::cl::Positional,
101 			llvm::cl::Required, llvm::cl::desc("<input file>"));
102 static llvm::cl::list<string> Includes("I",
103 			llvm::cl::desc("Header search path"),
104 			llvm::cl::value_desc("path"), llvm::cl::Prefix);
105 
106 static llvm::cl::opt<string> OutputLanguage(llvm::cl::Required,
107 	llvm::cl::ValueRequired, "language",
108 	llvm::cl::desc("Bindings to generate"),
109 	llvm::cl::value_desc("name"));
110 
111 static const char *ResourceDir =
112 	CLANG_PREFIX "/lib/clang/" CLANG_VERSION_STRING;
113 
114 /* Does decl have an attribute of the following form?
115  *
116  *	__attribute__((annotate("name")))
117  */
has_annotation(Decl * decl,const char * name)118 bool has_annotation(Decl *decl, const char *name)
119 {
120 	if (!decl->hasAttrs())
121 		return false;
122 
123 	AttrVec attrs = decl->getAttrs();
124 	for (AttrVec::const_iterator i = attrs.begin() ; i != attrs.end(); ++i) {
125 		const AnnotateAttr *ann = dyn_cast<AnnotateAttr>(*i);
126 		if (!ann)
127 			continue;
128 		if (ann->getAnnotation().str() == name)
129 			return true;
130 	}
131 
132 	return false;
133 }
134 
135 /* Is decl marked as exported?
136  */
is_exported(Decl * decl)137 static bool is_exported(Decl *decl)
138 {
139 	return has_annotation(decl, "isl_export");
140 }
141 
142 /* Collect all types and functions that are annotated "isl_export"
143  * in "exported_types" and "exported_function".  Collect all function
144  * declarations in "functions".
145  *
146  * We currently only consider single declarations.
147  */
148 struct MyASTConsumer : public ASTConsumer {
149 	set<RecordDecl *> exported_types;
150 	set<FunctionDecl *> exported_functions;
151 	set<FunctionDecl *> functions;
152 
HandleTopLevelDeclMyASTConsumer153 	virtual HandleTopLevelDeclReturn HandleTopLevelDecl(DeclGroupRef D) {
154 		Decl *decl;
155 
156 		if (!D.isSingleDecl())
157 			return HandleTopLevelDeclContinue;
158 		decl = D.getSingleDecl();
159 		if (isa<FunctionDecl>(decl))
160 			functions.insert(cast<FunctionDecl>(decl));
161 		if (!is_exported(decl))
162 			return HandleTopLevelDeclContinue;
163 		switch (decl->getKind()) {
164 		case Decl::Record:
165 			exported_types.insert(cast<RecordDecl>(decl));
166 			break;
167 		case Decl::Function:
168 			exported_functions.insert(cast<FunctionDecl>(decl));
169 			break;
170 		default:
171 			break;
172 		}
173 		return HandleTopLevelDeclContinue;
174 	}
175 };
176 
177 #ifdef USE_ARRAYREF
178 
179 #ifdef HAVE_CXXISPRODUCTION
construct_driver(const char * binary,DiagnosticsEngine & Diags)180 static Driver *construct_driver(const char *binary, DiagnosticsEngine &Diags)
181 {
182 	return new Driver(binary, llvm::sys::getDefaultTargetTriple(),
183 			    "", false, false, Diags);
184 }
185 #elif defined(HAVE_ISPRODUCTION)
construct_driver(const char * binary,DiagnosticsEngine & Diags)186 static Driver *construct_driver(const char *binary, DiagnosticsEngine &Diags)
187 {
188 	return new Driver(binary, llvm::sys::getDefaultTargetTriple(),
189 			    "", false, Diags);
190 }
191 #elif defined(DRIVER_CTOR_TAKES_DEFAULTIMAGENAME)
construct_driver(const char * binary,DiagnosticsEngine & Diags)192 static Driver *construct_driver(const char *binary, DiagnosticsEngine &Diags)
193 {
194 	return new Driver(binary, llvm::sys::getDefaultTargetTriple(),
195 			    "", Diags);
196 }
197 #else
construct_driver(const char * binary,DiagnosticsEngine & Diags)198 static Driver *construct_driver(const char *binary, DiagnosticsEngine &Diags)
199 {
200 	return new Driver(binary, llvm::sys::getDefaultTargetTriple(), Diags);
201 }
202 #endif
203 
204 namespace clang { namespace driver { class Job; } }
205 
206 /* Clang changed its API from 3.5 to 3.6 and once more in 3.7.
207  * We fix this with a simple overloaded function here.
208  */
209 struct ClangAPI {
commandClangAPI210 	static Job *command(Job *J) { return J; }
commandClangAPI211 	static Job *command(Job &J) { return &J; }
commandClangAPI212 	static Command *command(Command &C) { return &C; }
213 };
214 
215 #ifdef CREATE_FROM_ARGS_TAKES_ARRAYREF
216 
217 /* Call CompilerInvocation::CreateFromArgs with the right arguments.
218  * In this case, an ArrayRef<const char *>.
219  */
create_from_args(CompilerInvocation & invocation,const ArgStringList * args,DiagnosticsEngine & Diags)220 static void create_from_args(CompilerInvocation &invocation,
221 	const ArgStringList *args, DiagnosticsEngine &Diags)
222 {
223 	CompilerInvocation::CreateFromArgs(invocation, *args, Diags);
224 }
225 
226 #else
227 
228 /* Call CompilerInvocation::CreateFromArgs with the right arguments.
229  * In this case, two "const char *" pointers.
230  */
create_from_args(CompilerInvocation & invocation,const ArgStringList * args,DiagnosticsEngine & Diags)231 static void create_from_args(CompilerInvocation &invocation,
232 	const ArgStringList *args, DiagnosticsEngine &Diags)
233 {
234 	CompilerInvocation::CreateFromArgs(invocation, args->data() + 1,
235 						args->data() + args->size(),
236 						Diags);
237 }
238 
239 #endif
240 
241 #ifdef CLANG_SYSROOT
242 /* Set sysroot if required.
243  *
244  * If CLANG_SYSROOT is defined, then set it to this value.
245  */
set_sysroot(ArgStringList & args)246 static void set_sysroot(ArgStringList &args)
247 {
248 	args.push_back("-isysroot");
249 	args.push_back(CLANG_SYSROOT);
250 }
251 #else
252 /* Set sysroot if required.
253  *
254  * If CLANG_SYSROOT is not defined, then it does not need to be set.
255  */
set_sysroot(ArgStringList & args)256 static void set_sysroot(ArgStringList &args)
257 {
258 }
259 #endif
260 
261 /* Create a CompilerInvocation object that stores the command line
262  * arguments constructed by the driver.
263  * The arguments are mainly useful for setting up the system include
264  * paths on newer clangs and on some platforms.
265  */
construct_invocation(const char * filename,DiagnosticsEngine & Diags)266 static CompilerInvocation *construct_invocation(const char *filename,
267 	DiagnosticsEngine &Diags)
268 {
269 	const char *binary = CLANG_PREFIX"/bin/clang";
270 	const unique_ptr<Driver> driver(construct_driver(binary, Diags));
271 	std::vector<const char *> Argv;
272 	Argv.push_back(binary);
273 	Argv.push_back(filename);
274 	const unique_ptr<Compilation> compilation(
275 		driver->BuildCompilation(llvm::ArrayRef<const char *>(Argv)));
276 	JobList &Jobs = compilation->getJobs();
277 
278 	Command *cmd = cast<Command>(ClangAPI::command(*Jobs.begin()));
279 	if (strcmp(cmd->getCreator().getName(), "clang"))
280 		return NULL;
281 
282 	ArgStringList args = cmd->getArguments();
283 	set_sysroot(args);
284 
285 	CompilerInvocation *invocation = new CompilerInvocation;
286 	create_from_args(*invocation, &args, Diags);
287 	return invocation;
288 }
289 
290 #else
291 
construct_invocation(const char * filename,DiagnosticsEngine & Diags)292 static CompilerInvocation *construct_invocation(const char *filename,
293 	DiagnosticsEngine &Diags)
294 {
295 	return NULL;
296 }
297 
298 #endif
299 
300 #ifdef HAVE_BASIC_DIAGNOSTICOPTIONS_H
301 
construct_printer(void)302 static TextDiagnosticPrinter *construct_printer(void)
303 {
304 	return new TextDiagnosticPrinter(llvm::errs(), new DiagnosticOptions());
305 }
306 
307 #else
308 
construct_printer(void)309 static TextDiagnosticPrinter *construct_printer(void)
310 {
311 	DiagnosticOptions DO;
312 	return new TextDiagnosticPrinter(llvm::errs(), DO);
313 }
314 
315 #endif
316 
317 #ifdef CREATETARGETINFO_TAKES_SHARED_PTR
318 
create_target_info(CompilerInstance * Clang,DiagnosticsEngine & Diags)319 static TargetInfo *create_target_info(CompilerInstance *Clang,
320 	DiagnosticsEngine &Diags)
321 {
322 	shared_ptr<TargetOptions> TO = Clang->getInvocation().TargetOpts;
323 	TO->Triple = llvm::sys::getDefaultTargetTriple();
324 	return TargetInfo::CreateTargetInfo(Diags, TO);
325 }
326 
327 #elif defined(CREATETARGETINFO_TAKES_POINTER)
328 
create_target_info(CompilerInstance * Clang,DiagnosticsEngine & Diags)329 static TargetInfo *create_target_info(CompilerInstance *Clang,
330 	DiagnosticsEngine &Diags)
331 {
332 	TargetOptions &TO = Clang->getTargetOpts();
333 	TO.Triple = llvm::sys::getDefaultTargetTriple();
334 	return TargetInfo::CreateTargetInfo(Diags, &TO);
335 }
336 
337 #else
338 
create_target_info(CompilerInstance * Clang,DiagnosticsEngine & Diags)339 static TargetInfo *create_target_info(CompilerInstance *Clang,
340 	DiagnosticsEngine &Diags)
341 {
342 	TargetOptions &TO = Clang->getTargetOpts();
343 	TO.Triple = llvm::sys::getDefaultTargetTriple();
344 	return TargetInfo::CreateTargetInfo(Diags, TO);
345 }
346 
347 #endif
348 
349 #ifdef CREATEDIAGNOSTICS_TAKES_ARG
350 
create_diagnostics(CompilerInstance * Clang)351 static void create_diagnostics(CompilerInstance *Clang)
352 {
353 	Clang->createDiagnostics(0, NULL, construct_printer());
354 }
355 
356 #else
357 
create_diagnostics(CompilerInstance * Clang)358 static void create_diagnostics(CompilerInstance *Clang)
359 {
360 	Clang->createDiagnostics(construct_printer());
361 }
362 
363 #endif
364 
365 #ifdef CREATEPREPROCESSOR_TAKES_TUKIND
366 
create_preprocessor(CompilerInstance * Clang)367 static void create_preprocessor(CompilerInstance *Clang)
368 {
369 	Clang->createPreprocessor(TU_Complete);
370 }
371 
372 #else
373 
create_preprocessor(CompilerInstance * Clang)374 static void create_preprocessor(CompilerInstance *Clang)
375 {
376 	Clang->createPreprocessor();
377 }
378 
379 #endif
380 
381 #ifdef ADDPATH_TAKES_4_ARGUMENTS
382 
383 /* Add "Path" to the header search options.
384  *
385  * Do not take into account sysroot, i.e., set ignoreSysRoot to true.
386  */
add_path(HeaderSearchOptions & HSO,string Path)387 void add_path(HeaderSearchOptions &HSO, string Path)
388 {
389 	HSO.AddPath(Path, frontend::Angled, false, true);
390 }
391 
392 #else
393 
394 /* Add "Path" to the header search options.
395  *
396  * Do not take into account sysroot, i.e., set IsSysRootRelative to false.
397  */
add_path(HeaderSearchOptions & HSO,string Path)398 void add_path(HeaderSearchOptions &HSO, string Path)
399 {
400 	HSO.AddPath(Path, frontend::Angled, true, false, false);
401 }
402 
403 #endif
404 
405 #ifdef HAVE_SETMAINFILEID
406 
create_main_file_id(SourceManager & SM,const FileEntry * file)407 static void create_main_file_id(SourceManager &SM, const FileEntry *file)
408 {
409 	SM.setMainFileID(SM.createFileID(file, SourceLocation(),
410 					SrcMgr::C_User));
411 }
412 
413 #else
414 
create_main_file_id(SourceManager & SM,const FileEntry * file)415 static void create_main_file_id(SourceManager &SM, const FileEntry *file)
416 {
417 	SM.createMainFileID(file);
418 }
419 
420 #endif
421 
422 #ifdef SETLANGDEFAULTS_TAKES_5_ARGUMENTS
423 
424 #include "set_lang_defaults_arg4.h"
425 
set_lang_defaults(CompilerInstance * Clang)426 static void set_lang_defaults(CompilerInstance *Clang)
427 {
428 	PreprocessorOptions &PO = Clang->getPreprocessorOpts();
429 	TargetOptions &TO = Clang->getTargetOpts();
430 	llvm::Triple T(TO.Triple);
431 	CompilerInvocation::setLangDefaults(Clang->getLangOpts(), IK_C, T,
432 					    setLangDefaultsArg4(PO),
433 					    LangStandard::lang_unspecified);
434 }
435 
436 #else
437 
set_lang_defaults(CompilerInstance * Clang)438 static void set_lang_defaults(CompilerInstance *Clang)
439 {
440 	CompilerInvocation::setLangDefaults(Clang->getLangOpts(), IK_C,
441 					    LangStandard::lang_unspecified);
442 }
443 
444 #endif
445 
446 #ifdef SETINVOCATION_TAKES_SHARED_PTR
447 
set_invocation(CompilerInstance * Clang,CompilerInvocation * invocation)448 static void set_invocation(CompilerInstance *Clang,
449 	CompilerInvocation *invocation)
450 {
451 	Clang->setInvocation(std::make_shared<CompilerInvocation>(*invocation));
452 }
453 
454 #else
455 
set_invocation(CompilerInstance * Clang,CompilerInvocation * invocation)456 static void set_invocation(CompilerInstance *Clang,
457 	CompilerInvocation *invocation)
458 {
459 	Clang->setInvocation(invocation);
460 }
461 
462 #endif
463 
464 /* Helper function for ignore_error that only gets enabled if T
465  * (which is either const FileEntry * or llvm::ErrorOr<const FileEntry *>)
466  * has getError method, i.e., if it is llvm::ErrorOr<const FileEntry *>.
467  */
468 template <class T>
ignore_error_helper(const T obj,int,int[1][sizeof (obj.getError ())])469 static const FileEntry *ignore_error_helper(const T obj, int,
470 	int[1][sizeof(obj.getError())])
471 {
472 	return *obj;
473 }
474 
475 /* Helper function for ignore_error that is always enabled,
476  * but that only gets selected if the variant above is not enabled,
477  * i.e., if T is const FileEntry *.
478  */
479 template <class T>
ignore_error_helper(const T obj,long,void *)480 static const FileEntry *ignore_error_helper(const T obj, long, void *)
481 {
482 	return obj;
483 }
484 
485 /* Given either a const FileEntry * or a llvm::ErrorOr<const FileEntry *>,
486  * extract out the const FileEntry *.
487  */
488 template <class T>
ignore_error(const T obj)489 static const FileEntry *ignore_error(const T obj)
490 {
491 	return ignore_error_helper(obj, 0, NULL);
492 }
493 
494 /* Return the FileEntry corresponding to the given file name
495  * in the given compiler instances, ignoring any error.
496  */
getFile(CompilerInstance * Clang,std::string Filename)497 static const FileEntry *getFile(CompilerInstance *Clang, std::string Filename)
498 {
499 	return ignore_error(Clang->getFileManager().getFile(Filename));
500 }
501 
502 /* Create an interface generator for the selected language and
503  * then use it to generate the interface.
504  */
generate(MyASTConsumer & consumer,SourceManager & SM)505 static void generate(MyASTConsumer &consumer, SourceManager &SM)
506 {
507 	generator *gen;
508 
509 	if (OutputLanguage.compare("python") == 0) {
510 		gen = new python_generator(SM, consumer.exported_types,
511 			consumer.exported_functions, consumer.functions);
512 	} else if (OutputLanguage.compare("cpp") == 0) {
513 		gen = new plain_cpp_generator(SM, consumer.exported_types,
514 			consumer.exported_functions, consumer.functions);
515 	} else if (OutputLanguage.compare("cpp-checked") == 0) {
516 		gen = new plain_cpp_generator(SM, consumer.exported_types,
517 			consumer.exported_functions, consumer.functions, true);
518 	} else if (OutputLanguage.compare("cpp-checked-conversion") == 0) {
519 		gen = new cpp_conversion_generator(SM, consumer.exported_types,
520 			consumer.exported_functions, consumer.functions);
521 	} else if (OutputLanguage.compare("template-cpp") == 0) {
522 		gen = new template_cpp_generator(SM, consumer.exported_types,
523 			consumer.exported_functions, consumer.functions);
524 	} else {
525 		cerr << "Language '" << OutputLanguage
526 		     << "' not recognized." << endl
527 		     << "Not generating bindings." << endl;
528 		exit(EXIT_FAILURE);
529 	}
530 
531 	gen->generate();
532 }
533 
main(int argc,char * argv[])534 int main(int argc, char *argv[])
535 {
536 	llvm::cl::ParseCommandLineOptions(argc, argv);
537 
538 	CompilerInstance *Clang = new CompilerInstance();
539 	create_diagnostics(Clang);
540 	DiagnosticsEngine &Diags = Clang->getDiagnostics();
541 	Diags.setSuppressSystemWarnings(true);
542 	TargetInfo *target = create_target_info(Clang, Diags);
543 	Clang->setTarget(target);
544 	set_lang_defaults(Clang);
545 	CompilerInvocation *invocation =
546 		construct_invocation(InputFilename.c_str(), Diags);
547 	if (invocation)
548 		set_invocation(Clang, invocation);
549 	Clang->createFileManager();
550 	Clang->createSourceManager(Clang->getFileManager());
551 	HeaderSearchOptions &HSO = Clang->getHeaderSearchOpts();
552 	LangOptions &LO = Clang->getLangOpts();
553 	PreprocessorOptions &PO = Clang->getPreprocessorOpts();
554 	HSO.ResourceDir = ResourceDir;
555 
556 	for (llvm::cl::list<string>::size_type i = 0; i < Includes.size(); ++i)
557 		add_path(HSO, Includes[i]);
558 
559 	PO.addMacroDef("__isl_give=__attribute__((annotate(\"isl_give\")))");
560 	PO.addMacroDef("__isl_keep=__attribute__((annotate(\"isl_keep\")))");
561 	PO.addMacroDef("__isl_take=__attribute__((annotate(\"isl_take\")))");
562 	PO.addMacroDef("__isl_export=__attribute__((annotate(\"isl_export\")))");
563 	PO.addMacroDef("__isl_overload="
564 	    "__attribute__((annotate(\"isl_overload\"))) "
565 	    "__attribute__((annotate(\"isl_export\")))");
566 	PO.addMacroDef("__isl_constructor=__attribute__((annotate(\"isl_constructor\"))) __attribute__((annotate(\"isl_export\")))");
567 	PO.addMacroDef("__isl_subclass(super)=__attribute__((annotate(\"isl_subclass(\" #super \")\"))) __attribute__((annotate(\"isl_export\")))");
568 
569 	create_preprocessor(Clang);
570 	Preprocessor &PP = Clang->getPreprocessor();
571 
572 	PP.getBuiltinInfo().initializeBuiltins(PP.getIdentifierTable(), LO);
573 
574 	const FileEntry *file = getFile(Clang, InputFilename);
575 	assert(file);
576 	create_main_file_id(Clang->getSourceManager(), file);
577 
578 	Clang->createASTContext();
579 	MyASTConsumer consumer;
580 	Sema *sema = new Sema(PP, Clang->getASTContext(), consumer);
581 
582 	Diags.getClient()->BeginSourceFile(LO, &PP);
583 	ParseAST(*sema);
584 	Diags.getClient()->EndSourceFile();
585 
586 	generate(consumer, Clang->getSourceManager());
587 
588 	delete sema;
589 	delete Clang;
590 	llvm::llvm_shutdown();
591 
592 	if (Diags.hasErrorOccurred())
593 		return EXIT_FAILURE;
594 	return EXIT_SUCCESS;
595 }
596