1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | #include "clang/AST/ASTConsumer.h" |
10 | #include "clang/AST/ASTContext.h" |
11 | #include "clang/AST/RecursiveASTVisitor.h" |
12 | #include "clang/Basic/TargetInfo.h" |
13 | #include "clang/CodeGen/ModuleBuilder.h" |
14 | #include "clang/Frontend/CompilerInstance.h" |
15 | #include "clang/Lex/Preprocessor.h" |
16 | #include "clang/Parse/Parser.h" |
17 | #include "clang/Sema/Sema.h" |
18 | #include "llvm/ADT/Triple.h" |
19 | #include "llvm/IR/LLVMContext.h" |
20 | #include "llvm/IR/Module.h" |
21 | #include "llvm/Support/Host.h" |
22 | #include "llvm/Support/MemoryBuffer.h" |
23 | #include "gtest/gtest.h" |
24 | |
25 | #include <memory> |
26 | |
27 | using namespace llvm; |
28 | using namespace clang; |
29 | |
30 | namespace { |
31 | |
32 | |
33 | |
34 | const char TestProgram1[] = |
35 | "extern \"C\" int funcForProg1() { return 17; }\n" |
36 | "struct EmitCXXGlobalInitFunc1 {\n" |
37 | " EmitCXXGlobalInitFunc1() {}\n" |
38 | "} test1;"; |
39 | |
40 | const char TestProgram2[] = |
41 | "extern \"C\" int funcForProg2() { return 42; }\n" |
42 | "struct EmitCXXGlobalInitFunc2 {\n" |
43 | " EmitCXXGlobalInitFunc2() {}\n" |
44 | "} test2;"; |
45 | |
46 | |
47 | |
48 | static std::unique_ptr<llvm::Module> |
49 | IncrementalParseAST(CompilerInstance& CI, Parser& P, |
50 | CodeGenerator& CG, const char* code) { |
51 | static int counter = 0; |
52 | struct IncreaseCounterOnRet { |
53 | ~IncreaseCounterOnRet() { |
54 | ++counter; |
55 | } |
56 | } ICOR; |
57 | |
58 | Sema& S = CI.getSema(); |
59 | clang::SourceManager &SM = S.getSourceManager(); |
60 | if (!code) { |
61 | |
62 | SM.setMainFileID(SM.createFileID( |
63 | llvm::MemoryBuffer::getMemBuffer(" "), clang::SrcMgr::C_User)); |
64 | |
65 | S.getPreprocessor().EnterMainSourceFile(); |
66 | P.Initialize(); |
67 | } else { |
68 | FileID FID = SM.createFileID( |
69 | llvm::MemoryBuffer::getMemBuffer(code), clang::SrcMgr::C_User); |
70 | SourceLocation MainStartLoc = SM.getLocForStartOfFile(SM.getMainFileID()); |
71 | SourceLocation InclLoc = MainStartLoc.getLocWithOffset(counter); |
72 | S.getPreprocessor().EnterSourceFile(FID, 0, InclLoc); |
73 | } |
74 | |
75 | ExternalASTSource *External = S.getASTContext().getExternalSource(); |
76 | if (External) |
77 | External->StartTranslationUnit(&CG); |
78 | |
79 | Parser::DeclGroupPtrTy ADecl; |
80 | for (bool AtEOF = P.ParseFirstTopLevelDecl(ADecl); !AtEOF; |
81 | AtEOF = P.ParseTopLevelDecl(ADecl)) { |
82 | |
83 | |
84 | |
85 | if (ADecl && !CG.HandleTopLevelDecl(ADecl.get())) |
86 | return nullptr; |
87 | } |
88 | |
89 | |
90 | for (Decl *D : S.WeakTopLevelDecls()) |
91 | CG.HandleTopLevelDecl(DeclGroupRef(D)); |
92 | |
93 | CG.HandleTranslationUnit(S.getASTContext()); |
94 | |
95 | std::unique_ptr<llvm::Module> M(CG.ReleaseModule()); |
96 | |
97 | CG.StartModule("incremental-module-" + std::to_string(counter), |
98 | M->getContext()); |
99 | return M; |
100 | } |
101 | |
102 | const Function* getGlobalInit(llvm::Module& M) { |
103 | for (const auto& Func: M) |
104 | if (Func.hasName() && Func.getName().startswith("_GLOBAL__sub_I_")) |
105 | return &Func; |
106 | |
107 | return nullptr; |
108 | } |
109 | |
110 | TEST(IncrementalProcessing, EmitCXXGlobalInitFunc) { |
111 | LLVMContext Context; |
112 | CompilerInstance compiler; |
113 | |
114 | compiler.createDiagnostics(); |
115 | compiler.getLangOpts().CPlusPlus = 1; |
116 | compiler.getLangOpts().CPlusPlus11 = 1; |
117 | |
118 | compiler.getTargetOpts().Triple = llvm::Triple::normalize( |
119 | llvm::sys::getProcessTriple()); |
120 | compiler.setTarget(clang::TargetInfo::CreateTargetInfo( |
121 | compiler.getDiagnostics(), |
122 | std::make_shared<clang::TargetOptions>( |
123 | compiler.getTargetOpts()))); |
124 | |
125 | compiler.createFileManager(); |
126 | compiler.createSourceManager(compiler.getFileManager()); |
127 | compiler.createPreprocessor(clang::TU_Prefix); |
128 | compiler.getPreprocessor().enableIncrementalProcessing(); |
129 | |
130 | compiler.createASTContext(); |
131 | |
132 | CodeGenerator* CG = |
133 | CreateLLVMCodeGen( |
134 | compiler.getDiagnostics(), |
135 | "main-module", |
136 | compiler.getHeaderSearchOpts(), |
137 | compiler.getPreprocessorOpts(), |
138 | compiler.getCodeGenOpts(), |
139 | Context); |
140 | compiler.setASTConsumer(std::unique_ptr<ASTConsumer>(CG)); |
141 | compiler.createSema(clang::TU_Prefix, nullptr); |
142 | Sema& S = compiler.getSema(); |
143 | |
144 | std::unique_ptr<Parser> ParseOP(new Parser(S.getPreprocessor(), S, |
145 | false)); |
146 | Parser &P = *ParseOP.get(); |
147 | |
148 | std::array<std::unique_ptr<llvm::Module>, 3> M; |
149 | M[0] = IncrementalParseAST(compiler, P, *CG, nullptr); |
150 | ASSERT_TRUE(M[0]); |
151 | |
152 | M[1] = IncrementalParseAST(compiler, P, *CG, TestProgram1); |
153 | ASSERT_TRUE(M[1]); |
154 | ASSERT_TRUE(M[1]->getFunction("funcForProg1")); |
155 | |
156 | M[2] = IncrementalParseAST(compiler, P, *CG, TestProgram2); |
157 | ASSERT_TRUE(M[2]); |
158 | ASSERT_TRUE(M[2]->getFunction("funcForProg2")); |
159 | |
160 | ASSERT_FALSE(M[2]->getFunction("funcForProg1")); |
161 | |
162 | |
163 | const Function* GlobalInit1 = getGlobalInit(*M[1]); |
164 | ASSERT_TRUE(GlobalInit1); |
165 | |
166 | const Function* GlobalInit2 = getGlobalInit(*M[2]); |
167 | ASSERT_TRUE(GlobalInit2); |
168 | |
169 | ASSERT_FALSE(GlobalInit1->getName() == GlobalInit2->getName()); |
170 | |
171 | } |
172 | |
173 | } |
174 | |