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