1=============================== 2ASTImporter: Merging Clang ASTs 3=============================== 4 5The ``ASTImporter`` class is part of Clang's core library, the AST library. 6It imports nodes of an ``ASTContext`` into another ``ASTContext``. 7 8In this document, we assume basic knowledge about the Clang AST. See the :doc:`Introduction 9to the Clang AST <IntroductionToTheClangAST>` if you want to learn more 10about how the AST is structured. 11Knowledge about :doc:`matching the Clang AST <LibASTMatchers>` and the `reference for the matchers <https://clang.llvm.org/docs/LibASTMatchersReference.html>`_ are also useful. 12 13.. contents:: 14 :local: 15 16Introduction 17------------ 18 19``ASTContext`` holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic analysis of a file. 20In some cases it is preferable to work with more than one ``ASTContext``. 21For example, we'd like to parse multiple different files inside the same Clang tool. 22It may be convenient if we could view the set of the resulting ASTs as if they were one AST resulting from the parsing of each file together. 23``ASTImporter`` provides the way to copy types or declarations from one ``ASTContext`` to another. 24We refer to the context from which we import as the **"from" context** or *source context*; and the context into which we import as the **"to" context** or *destination context*. 25 26Existing clients of the ``ASTImporter`` library are Cross Translation Unit (CTU) static analysis and the LLDB expression parser. 27CTU static analysis imports a definition of a function if its definition is found in another translation unit (TU). 28This way the analysis can breach out from the single TU limitation. 29LLDB's ``expr`` command parses a user-defined expression, creates an ``ASTContext`` for that and then imports the missing definitions from the AST what we got from the debug information (DWARF, etc). 30 31Algorithm of the import 32----------------------- 33 34Importing one AST node copies that node into the destination ``ASTContext``. 35Why do we have to copy the node? 36Isn't enough to insert the pointer to that node into the destination context? 37One reason is that the "from" context may outlive the "to" context. 38Also, the Clang AST consider nodes (or certain properties of nodes) equivalent if they have the same address! 39 40The import algorithm has to ensure that the structurally equivalent nodes in the different translation units are not getting duplicated in the merged AST. 41E.g. if we include the definition of the vector template (``#include <vector>``) in two translation units, then their merged AST should have only one node which represents the template. 42Also, we have to discover *one definition rule* (ODR) violations. 43For instance, if there is a class definition with the same name in both translation units, but one of the definition contains a different number of fields. 44So, we look up existing definitions, and then we check the structural equivalency on those nodes. 45The following pseudo-code demonstrates the basics of the import mechanism: 46 47.. code-block:: cpp 48 49 // Pseudo-code(!) of import: 50 ErrorOrDecl Import(Decl *FromD) { 51 Decl *ToDecl = nullptr; 52 FoundDeclsList = Look up all Decls in the "to" Ctx with the same name of FromD; 53 for (auto FoundDecl : FoundDeclsList) { 54 if (StructurallyEquivalentDecls(FoundDecl, FromD)) { 55 ToDecl = FoundDecl; 56 Mark FromD as imported; 57 break; 58 } else { 59 Report ODR violation; 60 return error; 61 } 62 } 63 if (FoundDeclsList is empty) { 64 Import dependent declarations and types of ToDecl; 65 ToDecl = create a new AST node in "to" Ctx; 66 Mark FromD as imported; 67 } 68 return ToDecl; 69 } 70 71Two AST nodes are *structurally equivalent* if they are 72 73- builtin types and refer to the same type, e.g. ``int`` and ``int`` are structurally equivalent, 74- function types and all their parameters have structurally equivalent types, 75- record types and all their fields in order of their definition have the same identifier names and structurally equivalent types, 76- variable or function declarations and they have the same identifier name and their types are structurally equivalent. 77 78We could extend the definition of structural equivalency to templates similarly. 79 80If A and B are AST nodes and *A depends on B*, then we say that A is a **dependant** of B and B is a **dependency** of A. 81The words "dependant" and "dependency" are nouns in British English. 82Unfortunately, in American English, the adjective "dependent" is used for both meanings. 83In this document, with the "dependent" adjective we always address the dependencies, the B node in the example. 84 85API 86--- 87 88Let's create a tool which uses the ASTImporter class! 89First, we build two ASTs from virtual files; the content of the virtual files are synthesized from string literals: 90 91.. code-block:: cpp 92 93 std::unique_ptr<ASTUnit> ToUnit = buildASTFromCode( 94 "", "to.cc"); // empty file 95 std::unique_ptr<ASTUnit> FromUnit = buildASTFromCode( 96 R"( 97 class MyClass { 98 int m1; 99 int m2; 100 }; 101 )", 102 "from.cc"); 103 104The first AST corresponds to the destination ("to") context - which is empty - and the second for the source ("from") context. 105Next, we define a matcher to match ``MyClass`` in the "from" context: 106 107.. code-block:: cpp 108 109 auto Matcher = cxxRecordDecl(hasName("MyClass")); 110 auto *From = getFirstDecl<CXXRecordDecl>(Matcher, FromUnit); 111 112Now we create the Importer and do the import: 113 114.. code-block:: cpp 115 116 ASTImporter Importer(ToUnit->getASTContext(), ToUnit->getFileManager(), 117 FromUnit->getASTContext(), FromUnit->getFileManager(), 118 /*MinimalImport=*/true); 119 llvm::Expected<Decl *> ImportedOrErr = Importer.Import(From); 120 121The ``Import`` call returns with ``llvm::Expected``, so, we must check for any error. 122Please refer to the `error handling <https://llvm.org/docs/ProgrammersManual.html#recoverable-errors>`_ documentation for details. 123 124.. code-block:: cpp 125 126 if (!ImportedOrErr) { 127 llvm::Error Err = ImportedOrErr.takeError(); 128 llvm::errs() << "ERROR: " << Err << "\n"; 129 consumeError(std::move(Err)); 130 return 1; 131 } 132 133If there's no error then we can get the underlying value. 134In this example we will print the AST of the "to" context. 135 136.. code-block:: cpp 137 138 Decl *Imported = *ImportedOrErr; 139 Imported->getTranslationUnitDecl()->dump(); 140 141Since we set **minimal import** in the constructor of the importer, the AST will not contain the declaration of the members (once we run the test tool). 142 143.. code-block:: bash 144 145 TranslationUnitDecl 0x68b9a8 <<invalid sloc>> <invalid sloc> 146 `-CXXRecordDecl 0x6c7e30 <line:2:7, col:13> col:13 class MyClass definition 147 `-DefinitionData pass_in_registers standard_layout trivially_copyable trivial literal 148 |-DefaultConstructor exists trivial needs_implicit 149 |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param 150 |-MoveConstructor exists simple trivial needs_implicit 151 |-CopyAssignment trivial has_const_param needs_implicit implicit_has_const_param 152 |-MoveAssignment exists simple trivial needs_implicit 153 `-Destructor simple irrelevant trivial needs_implicit 154 155We'd like to get the members too, so, we use ``ImportDefinition`` to copy the whole definition of ``MyClass`` into the "to" context. 156Then we dump the AST again. 157 158.. code-block:: cpp 159 160 if (llvm::Error Err = Importer.ImportDefinition(From)) { 161 llvm::errs() << "ERROR: " << Err << "\n"; 162 consumeError(std::move(Err)); 163 return 1; 164 } 165 llvm::errs() << "Imported definition.\n"; 166 Imported->getTranslationUnitDecl()->dump(); 167 168This time the AST is going to contain the members too. 169 170.. code-block:: bash 171 172 TranslationUnitDecl 0x68b9a8 <<invalid sloc>> <invalid sloc> 173 `-CXXRecordDecl 0x6c7e30 <line:2:7, col:13> col:13 class MyClass definition 174 |-DefinitionData pass_in_registers standard_layout trivially_copyable trivial literal 175 | |-DefaultConstructor exists trivial needs_implicit 176 | |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param 177 | |-MoveConstructor exists simple trivial needs_implicit 178 | |-CopyAssignment trivial has_const_param needs_implicit implicit_has_const_param 179 | |-MoveAssignment exists simple trivial needs_implicit 180 | `-Destructor simple irrelevant trivial needs_implicit 181 |-CXXRecordDecl 0x6c7f48 <col:7, col:13> col:13 implicit class MyClass 182 |-FieldDecl 0x6c7ff0 <line:3:9, col:13> col:13 m1 'int' 183 `-FieldDecl 0x6c8058 <line:4:9, col:13> col:13 m2 'int' 184 185We can spare the call for ``ImportDefinition`` if we set up the importer to do a "normal" (not minimal) import. 186 187.. code-block:: cpp 188 189 ASTImporter Importer( .... /*MinimalImport=*/false); 190 191With **normal import**, all dependent declarations are imported normally. 192However, with minimal import, the dependent Decls are imported without definition, and we have to import their definition for each if we later need that. 193 194Putting this all together here is how the source of the tool looks like: 195 196.. code-block:: cpp 197 198 #include "clang/AST/ASTImporter.h" 199 #include "clang/ASTMatchers/ASTMatchFinder.h" 200 #include "clang/ASTMatchers/ASTMatchers.h" 201 #include "clang/Tooling/Tooling.h" 202 203 using namespace clang; 204 using namespace tooling; 205 using namespace ast_matchers; 206 207 template <typename Node, typename Matcher> 208 Node *getFirstDecl(Matcher M, const std::unique_ptr<ASTUnit> &Unit) { 209 auto MB = M.bind("bindStr"); // Bind the to-be-matched node to a string key. 210 auto MatchRes = match(MB, Unit->getASTContext()); 211 // We should have at least one match. 212 assert(MatchRes.size() >= 1); 213 // Get the first matched and bound node. 214 Node *Result = 215 const_cast<Node *>(MatchRes[0].template getNodeAs<Node>("bindStr")); 216 assert(Result); 217 return Result; 218 } 219 220 int main() { 221 std::unique_ptr<ASTUnit> ToUnit = buildASTFromCode( 222 "", "to.cc"); 223 std::unique_ptr<ASTUnit> FromUnit = buildASTFromCode( 224 R"( 225 class MyClass { 226 int m1; 227 int m2; 228 }; 229 )", 230 "from.cc"); 231 auto Matcher = cxxRecordDecl(hasName("MyClass")); 232 auto *From = getFirstDecl<CXXRecordDecl>(Matcher, FromUnit); 233 234 ASTImporter Importer(ToUnit->getASTContext(), ToUnit->getFileManager(), 235 FromUnit->getASTContext(), FromUnit->getFileManager(), 236 /*MinimalImport=*/true); 237 llvm::Expected<Decl *> ImportedOrErr = Importer.Import(From); 238 if (!ImportedOrErr) { 239 llvm::Error Err = ImportedOrErr.takeError(); 240 llvm::errs() << "ERROR: " << Err << "\n"; 241 consumeError(std::move(Err)); 242 return 1; 243 } 244 Decl *Imported = *ImportedOrErr; 245 Imported->getTranslationUnitDecl()->dump(); 246 247 if (llvm::Error Err = Importer.ImportDefinition(From)) { 248 llvm::errs() << "ERROR: " << Err << "\n"; 249 consumeError(std::move(Err)); 250 return 1; 251 } 252 llvm::errs() << "Imported definition.\n"; 253 Imported->getTranslationUnitDecl()->dump(); 254 255 return 0; 256 }; 257 258We may extend the ``CMakeLists.txt`` under let's say ``clang/tools`` with the build and link instructions: 259 260.. code-block:: bash 261 262 add_clang_executable(astimporter-demo ASTImporterDemo.cpp) 263 clang_target_link_libraries(astimporter-demo 264 PRIVATE 265 LLVMSupport 266 clangAST 267 clangASTMatchers 268 clangBasic 269 clangFrontend 270 clangSerialization 271 clangTooling 272 ) 273 274Then we can build and execute the new tool. 275 276.. code-block:: bash 277 278 $ ninja astimporter-demo && ./bin/astimporter-demo 279 280Errors during the import process 281^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 282 283Normally, either the source or the destination context contains the definition of a declaration. 284However, there may be cases when both of the contexts have a definition for a given symbol. 285If these definitions differ, then we have a name conflict, in C++ it is known as ODR (one definition rule) violation. 286Let's modify the previous tool we had written and try to import a ``ClassTemplateSpecializationDecl`` with a conflicting definition: 287 288.. code-block:: cpp 289 290 int main() { 291 std::unique_ptr<ASTUnit> ToUnit = buildASTFromCode( 292 R"( 293 // primary template 294 template <typename T> 295 struct X {}; 296 // explicit specialization 297 template<> 298 struct X<int> { int i; }; 299 )", 300 "to.cc"); 301 ToUnit->enableSourceFileDiagnostics(); 302 std::unique_ptr<ASTUnit> FromUnit = buildASTFromCode( 303 R"( 304 // primary template 305 template <typename T> 306 struct X {}; 307 // explicit specialization 308 template<> 309 struct X<int> { int i2; }; 310 // field mismatch: ^^ 311 )", 312 "from.cc"); 313 FromUnit->enableSourceFileDiagnostics(); 314 auto Matcher = classTemplateSpecializationDecl(hasName("X")); 315 auto *From = getFirstDecl<ClassTemplateSpecializationDecl>(Matcher, FromUnit); 316 auto *To = getFirstDecl<ClassTemplateSpecializationDecl>(Matcher, ToUnit); 317 318 ASTImporter Importer(ToUnit->getASTContext(), ToUnit->getFileManager(), 319 FromUnit->getASTContext(), FromUnit->getFileManager(), 320 /*MinimalImport=*/false); 321 llvm::Expected<Decl *> ImportedOrErr = Importer.Import(From); 322 if (!ImportedOrErr) { 323 llvm::Error Err = ImportedOrErr.takeError(); 324 llvm::errs() << "ERROR: " << Err << "\n"; 325 consumeError(std::move(Err)); 326 To->getTranslationUnitDecl()->dump(); 327 return 1; 328 } 329 return 0; 330 }; 331 332When we run the tool we have the following warning: 333 334.. code-block:: bash 335 336 to.cc:7:14: warning: type 'X<int>' has incompatible definitions in different translation units [-Wodr] 337 struct X<int> { int i; }; 338 ^ 339 to.cc:7:27: note: field has name 'i' here 340 struct X<int> { int i; }; 341 ^ 342 from.cc:7:27: note: field has name 'i2' here 343 struct X<int> { int i2; }; 344 ^ 345 346Note, because of these diagnostics we had to call ``enableSourceFileDiagnostics`` on the ``ASTUnit`` objects. 347 348Since we could not import the specified declaration (``From``), we get an error in the return value. 349The AST does not contain the conflicting definition, so we are left with the original AST. 350 351.. code-block:: bash 352 353 ERROR: NameConflict 354 TranslationUnitDecl 0xe54a48 <<invalid sloc>> <invalid sloc> 355 |-ClassTemplateDecl 0xe91020 <to.cc:3:7, line:4:17> col:14 X 356 | |-TemplateTypeParmDecl 0xe90ed0 <line:3:17, col:26> col:26 typename depth 0 index 0 T 357 | |-CXXRecordDecl 0xe90f90 <line:4:7, col:17> col:14 struct X definition 358 | | |-DefinitionData empty aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor can_const_default_init 359 | | | |-DefaultConstructor exists trivial constexpr needs_implicit defaulted_is_constexpr 360 | | | |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param 361 | | | |-MoveConstructor exists simple trivial needs_implicit 362 | | | |-CopyAssignment trivial has_const_param needs_implicit implicit_has_const_param 363 | | | |-MoveAssignment exists simple trivial needs_implicit 364 | | | `-Destructor simple irrelevant trivial needs_implicit 365 | | `-CXXRecordDecl 0xe91270 <col:7, col:14> col:14 implicit struct X 366 | `-ClassTemplateSpecialization 0xe91340 'X' 367 `-ClassTemplateSpecializationDecl 0xe91340 <line:6:7, line:7:30> col:14 struct X definition 368 |-DefinitionData pass_in_registers aggregate standard_layout trivially_copyable pod trivial literal 369 | |-DefaultConstructor exists trivial needs_implicit 370 | |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param 371 | |-MoveConstructor exists simple trivial needs_implicit 372 | |-CopyAssignment trivial has_const_param needs_implicit implicit_has_const_param 373 | |-MoveAssignment exists simple trivial needs_implicit 374 | `-Destructor simple irrelevant trivial needs_implicit 375 |-TemplateArgument type 'int' 376 |-CXXRecordDecl 0xe91558 <col:7, col:14> col:14 implicit struct X 377 `-FieldDecl 0xe91600 <col:23, col:27> col:27 i 'int' 378 379Error propagation 380""""""""""""""""" 381 382If there is a dependent node we have to import before we could import a given node then the import error associated to the dependency propagates to the dependant node. 383Let's modify the previous example and import a ``FieldDecl`` instead of the ``ClassTemplateSpecializationDecl``. 384 385.. code-block:: cpp 386 387 auto Matcher = fieldDecl(hasName("i2")); 388 auto *From = getFirstDecl<FieldDecl>(Matcher, FromUnit); 389 390In this case we can see that an error is associated (``getImportDeclErrorIfAny``) to the specialization also, not just to the field: 391 392.. code-block:: cpp 393 394 llvm::Expected<Decl *> ImportedOrErr = Importer.Import(From); 395 if (!ImportedOrErr) { 396 llvm::Error Err = ImportedOrErr.takeError(); 397 consumeError(std::move(Err)); 398 399 // check that the ClassTemplateSpecializationDecl is also marked as 400 // erroneous. 401 auto *FromSpec = getFirstDecl<ClassTemplateSpecializationDecl>( 402 classTemplateSpecializationDecl(hasName("X")), FromUnit); 403 assert(Importer.getImportDeclErrorIfAny(FromSpec)); 404 // Btw, the error is also set for the FieldDecl. 405 assert(Importer.getImportDeclErrorIfAny(From)); 406 return 1; 407 } 408 409Polluted AST 410"""""""""""" 411 412We may recognize an error during the import of a dependent node. However, by that time, we had already created the dependant. 413In these cases we do not remove the existing erroneous node from the "to" context, rather we associate an error to that node. 414Let's extend the previous example with another class ``Y``. 415This class has a forward definition in the "to" context, but its definition is in the "from" context. 416We'd like to import the definition, but it contains a member whose type conflicts with the type in the "to" context: 417 418.. code-block:: cpp 419 420 std::unique_ptr<ASTUnit> ToUnit = buildASTFromCode( 421 R"( 422 // primary template 423 template <typename T> 424 struct X {}; 425 // explicit specialization 426 template<> 427 struct X<int> { int i; }; 428 429 class Y; 430 )", 431 "to.cc"); 432 ToUnit->enableSourceFileDiagnostics(); 433 std::unique_ptr<ASTUnit> FromUnit = buildASTFromCode( 434 R"( 435 // primary template 436 template <typename T> 437 struct X {}; 438 // explicit specialization 439 template<> 440 struct X<int> { int i2; }; 441 // field mismatch: ^^ 442 443 class Y { void f() { X<int> xi; } }; 444 )", 445 "from.cc"); 446 FromUnit->enableSourceFileDiagnostics(); 447 auto Matcher = cxxRecordDecl(hasName("Y")); 448 auto *From = getFirstDecl<CXXRecordDecl>(Matcher, FromUnit); 449 auto *To = getFirstDecl<CXXRecordDecl>(Matcher, ToUnit); 450 451This time we create a shared_ptr for ``ASTImporterSharedState`` which owns the associated errors for the "to" context. 452Note, there may be several different ASTImporter objects which import into the same "to" context but from different "from" contexts; they should share the same ``ASTImporterSharedState``. 453(Also note, we have to include the corresponding ``ASTImporterSharedState.h`` header file.) 454 455.. code-block:: cpp 456 457 auto ImporterState = std::make_shared<ASTImporterSharedState>(); 458 ASTImporter Importer(ToUnit->getASTContext(), ToUnit->getFileManager(), 459 FromUnit->getASTContext(), FromUnit->getFileManager(), 460 /*MinimalImport=*/false, ImporterState); 461 llvm::Expected<Decl *> ImportedOrErr = Importer.Import(From); 462 if (!ImportedOrErr) { 463 llvm::Error Err = ImportedOrErr.takeError(); 464 consumeError(std::move(Err)); 465 466 // ... but the node had been created. 467 auto *ToYDef = getFirstDecl<CXXRecordDecl>( 468 cxxRecordDecl(hasName("Y"), isDefinition()), ToUnit); 469 ToYDef->dump(); 470 // An error is set for "ToYDef" in the shared state. 471 Optional<ImportError> OptErr = 472 ImporterState->getImportDeclErrorIfAny(ToYDef); 473 assert(OptErr); 474 475 return 1; 476 } 477 478If we take a look at the AST, then we can see that the Decl with the definition is created, but the field is missing. 479 480.. code-block:: bash 481 482 |-CXXRecordDecl 0xf66678 <line:9:7, col:13> col:13 class Y 483 `-CXXRecordDecl 0xf66730 prev 0xf66678 <:10:7, col:13> col:13 class Y definition 484 |-DefinitionData pass_in_registers empty aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor can_const_default_init 485 | |-DefaultConstructor exists trivial constexpr needs_implicit defaulted_is_constexpr 486 | |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param 487 | |-MoveConstructor exists simple trivial needs_implicit 488 | |-CopyAssignment trivial has_const_param needs_implicit implicit_has_const_param 489 | |-MoveAssignment exists simple trivial needs_implicit 490 | `-Destructor simple irrelevant trivial needs_implicit 491 `-CXXRecordDecl 0xf66828 <col:7, col:13> col:13 implicit class Y 492 493We do not remove the erroneous nodes because by the time when we recognize the error it is too late to remove the node, there may be additional references to that already in the AST. 494This is aligned with the overall `design principle of the Clang AST <InternalsManual.html#immutability>`_: Clang AST nodes (types, declarations, statements, expressions, and so on) are generally designed to be **immutable once created**. 495Thus, clients of the ASTImporter library should always check if there is any associated error for the node which they inspect in the destination context. 496We recommend skipping the processing of those nodes which have an error associated with them. 497 498Using the ``-ast-merge`` Clang front-end action 499----------------------------------------------- 500 501The ``-ast-merge <pch-file>`` command-line switch can be used to merge from the given serialized AST file. 502This file represents the source context. 503When this switch is present then each top-level AST node of the source context is being merged into the destination context. 504If the merge was successful then ``ASTConsumer::HandleTopLevelDecl`` is called for the Decl. 505This results that we can execute the original front-end action on the extended AST. 506 507Example for C 508^^^^^^^^^^^^^ 509 510Let's consider the following three files: 511 512.. code-block:: c 513 514 // bar.h 515 #ifndef BAR_H 516 #define BAR_H 517 int bar(); 518 #endif /* BAR_H */ 519 520 // bar.c 521 #include "bar.h" 522 int bar() { 523 return 41; 524 } 525 526 // main.c 527 #include "bar.h" 528 int main() { 529 return bar(); 530 } 531 532Let's generate the AST files for the two source files: 533 534.. code-block:: bash 535 536 $ clang -cc1 -emit-pch -o bar.ast bar.c 537 $ clang -cc1 -emit-pch -o main.ast main.c 538 539Then, let's check how the merged AST would look like if we consider only the ``bar()`` function: 540 541.. code-block:: bash 542 543 $ clang -cc1 -ast-merge bar.ast -ast-merge main.ast /dev/null -ast-dump 544 TranslationUnitDecl 0x12b0738 <<invalid sloc>> <invalid sloc> 545 |-FunctionDecl 0x12b1470 </path/bar.h:4:1, col:9> col:5 used bar 'int ()' 546 |-FunctionDecl 0x12b1538 prev 0x12b1470 </path/bar.c:3:1, line:5:1> line:3:5 used bar 'int ()' 547 | `-CompoundStmt 0x12b1608 <col:11, line:5:1> 548 | `-ReturnStmt 0x12b15f8 <line:4:3, col:10> 549 | `-IntegerLiteral 0x12b15d8 <col:10> 'int' 41 550 |-FunctionDecl 0x12b1648 prev 0x12b1538 </path/bar.h:4:1, col:9> col:5 used bar 'int ()' 551 552We can inspect that the prototype of the function and the definition of it is merged into the same redeclaration chain. 553What's more there is a third prototype declaration merged to the chain. 554The functions are merged in a way that prototypes are added to the redecl chain if they refer to the same type, but we can have only one definition. 555The first two declarations are from ``bar.ast``, the third is from ``main.ast``. 556 557Now, let's create an object file from the merged AST: 558 559.. code-block:: bash 560 561 $ clang -cc1 -ast-merge bar.ast -ast-merge main.ast /dev/null -emit-obj -o main.o 562 563Next, we may call the linker and execute the created binary file. 564 565.. code-block:: bash 566 567 $ clang -o a.out main.o 568 $ ./a.out 569 $ echo $? 570 41 571 $ 572 573Example for C++ 574^^^^^^^^^^^^^^^ 575 576In the case of C++, the generation of the AST files and the way how we invoke the front-end is a bit different. 577Assuming we have these three files: 578 579.. code-block:: cpp 580 581 // foo.h 582 #ifndef FOO_H 583 #define FOO_H 584 struct foo { 585 virtual int fun(); 586 }; 587 #endif /* FOO_H */ 588 589 // foo.cpp 590 #include "foo.h" 591 int foo::fun() { 592 return 42; 593 } 594 595 // main.cpp 596 #include "foo.h" 597 int main() { 598 return foo().fun(); 599 } 600 601We shall generate the AST files, merge them, create the executable and then run it: 602 603.. code-block:: bash 604 605 $ clang++ -x c++-header -o foo.ast foo.cpp 606 $ clang++ -x c++-header -o main.ast main.cpp 607 $ clang++ -cc1 -x c++ -ast-merge foo.ast -ast-merge main.ast /dev/null -ast-dump 608 $ clang++ -cc1 -x c++ -ast-merge foo.ast -ast-merge main.ast /dev/null -emit-obj -o main.o 609 $ clang++ -o a.out main.o 610 $ ./a.out 611 $ echo $? 612 42 613 $ 614