[SCCP] Avoid modifying AdditionalUsers while iterating over it
[llvm-project.git] / clang / unittests / CodeGen / IncrementalProcessingTest.cpp
blobfed8ecd59f35da35d84ff14e22b05b58eb846e4e
1 //=== unittests/CodeGen/IncrementalProcessingTest.cpp - IncrementalCodeGen ===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
9 #include "TestCompiler.h"
11 #include "clang/AST/ASTConsumer.h"
12 #include "clang/AST/ASTContext.h"
13 #include "clang/AST/RecursiveASTVisitor.h"
14 #include "clang/Basic/TargetInfo.h"
15 #include "clang/CodeGen/ModuleBuilder.h"
16 #include "clang/Frontend/CompilerInstance.h"
17 #include "clang/Lex/Preprocessor.h"
18 #include "clang/Parse/Parser.h"
19 #include "clang/Sema/Sema.h"
20 #include "llvm/ADT/Triple.h"
21 #include "llvm/IR/LLVMContext.h"
22 #include "llvm/IR/Module.h"
23 #include "llvm/Support/Host.h"
24 #include "llvm/Support/MemoryBuffer.h"
25 #include "gtest/gtest.h"
27 #include <memory>
29 using namespace llvm;
30 using namespace clang;
32 namespace {
34 // Incremental processing produces several modules, all using the same "main
35 // file". Make sure CodeGen can cope with that, e.g. for static initializers.
36 const char TestProgram1[] =
37 "extern \"C\" int funcForProg1() { return 17; }\n"
38 "struct EmitCXXGlobalInitFunc1 {\n"
39 " EmitCXXGlobalInitFunc1() {}\n"
40 "} test1;";
42 const char TestProgram2[] =
43 "extern \"C\" int funcForProg2() { return 42; }\n"
44 "struct EmitCXXGlobalInitFunc2 {\n"
45 " EmitCXXGlobalInitFunc2() {}\n"
46 "} test2;";
49 /// An incremental version of ParseAST().
50 static std::unique_ptr<llvm::Module>
51 IncrementalParseAST(CompilerInstance& CI, Parser& P,
52 CodeGenerator& CG, const char* code) {
53 static int counter = 0;
54 struct IncreaseCounterOnRet {
55 ~IncreaseCounterOnRet() {
56 ++counter;
58 } ICOR;
60 Sema& S = CI.getSema();
61 clang::SourceManager &SM = S.getSourceManager();
62 if (!code) {
63 // Main file
64 SM.setMainFileID(SM.createFileID(
65 llvm::MemoryBuffer::getMemBuffer(" "), clang::SrcMgr::C_User));
67 S.getPreprocessor().EnterMainSourceFile();
68 P.Initialize();
69 } else {
70 FileID FID = SM.createFileID(
71 llvm::MemoryBuffer::getMemBuffer(code), clang::SrcMgr::C_User);
72 SourceLocation MainStartLoc = SM.getLocForStartOfFile(SM.getMainFileID());
73 SourceLocation InclLoc = MainStartLoc.getLocWithOffset(counter);
74 S.getPreprocessor().EnterSourceFile(FID, 0, InclLoc);
77 ExternalASTSource *External = S.getASTContext().getExternalSource();
78 if (External)
79 External->StartTranslationUnit(&CG);
81 Parser::DeclGroupPtrTy ADecl;
82 for (bool AtEOF = P.ParseFirstTopLevelDecl(ADecl); !AtEOF;
83 AtEOF = P.ParseTopLevelDecl(ADecl)) {
84 // If we got a null return and something *was* parsed, ignore it. This
85 // is due to a top-level semicolon, an action override, or a parse error
86 // skipping something.
87 if (ADecl && !CG.HandleTopLevelDecl(ADecl.get()))
88 return nullptr;
91 // Process any TopLevelDecls generated by #pragma weak.
92 for (Decl *D : S.WeakTopLevelDecls())
93 CG.HandleTopLevelDecl(DeclGroupRef(D));
95 CG.HandleTranslationUnit(S.getASTContext());
97 std::unique_ptr<llvm::Module> M(CG.ReleaseModule());
98 // Switch to next module.
99 CG.StartModule("incremental-module-" + std::to_string(counter),
100 M->getContext());
101 return M;
104 const Function* getGlobalInit(llvm::Module& M) {
105 for (const auto& Func: M)
106 if (Func.hasName() && Func.getName().startswith("_GLOBAL__sub_I_"))
107 return &Func;
109 return nullptr;
112 TEST(IncrementalProcessing, EmitCXXGlobalInitFunc) {
113 clang::LangOptions LO;
114 LO.CPlusPlus = 1;
115 LO.CPlusPlus11 = 1;
116 TestCompiler Compiler(LO);
117 clang::CompilerInstance &CI = Compiler.compiler;
118 CI.getPreprocessor().enableIncrementalProcessing();
119 CI.setASTConsumer(std::move(Compiler.CG));
120 clang::CodeGenerator& CG =
121 static_cast<clang::CodeGenerator&>(CI.getASTConsumer());
122 CI.createSema(clang::TU_Prefix, nullptr);
124 Sema& S = CI.getSema();
126 std::unique_ptr<Parser> ParseOP(new Parser(S.getPreprocessor(), S,
127 /*SkipFunctionBodies*/ false));
128 Parser &P = *ParseOP.get();
130 std::array<std::unique_ptr<llvm::Module>, 3> M;
131 M[0] = IncrementalParseAST(CI, P, CG, nullptr);
132 ASSERT_TRUE(M[0]);
134 M[1] = IncrementalParseAST(CI, P, CG, TestProgram1);
135 ASSERT_TRUE(M[1]);
136 ASSERT_TRUE(M[1]->getFunction("funcForProg1"));
138 M[2] = IncrementalParseAST(CI, P, CG, TestProgram2);
139 ASSERT_TRUE(M[2]);
140 ASSERT_TRUE(M[2]->getFunction("funcForProg2"));
141 // First code should not end up in second module:
142 ASSERT_FALSE(M[2]->getFunction("funcForProg1"));
144 // Make sure global inits exist and are unique:
145 const Function* GlobalInit1 = getGlobalInit(*M[1]);
146 ASSERT_TRUE(GlobalInit1);
148 const Function* GlobalInit2 = getGlobalInit(*M[2]);
149 ASSERT_TRUE(GlobalInit2);
151 ASSERT_FALSE(GlobalInit1->getName() == GlobalInit2->getName());
155 } // end anonymous namespace