Skip to content

Commit ef0b054

Browse files
committed
Split Parser::ParseHeader into helper methods.
Use clang::SemaConsumer interface callback to walk over the parsed AST. This deals with a nasty bug that occurs when processing late-parsed template declarations. The clang::Parser object life is tied to clang::ParseAST function, so we need to process the AST in the callback. Fixes #1123 and (hopefully) #1124.
1 parent e88b1a8 commit ef0b054

File tree

3 files changed

+117
-59
lines changed

3 files changed

+117
-59
lines changed

src/CppParser/Parser.cpp

Lines changed: 77 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,7 @@
4444
#include <clang/Driver/ToolChain.h>
4545
#include <clang/Driver/Util.h>
4646
#include <clang/Index/USRGeneration.h>
47-
#include <CodeGen/CodeGenModule.h>
48-
#include <CodeGen/CodeGenTypes.h>
47+
4948
#include <CodeGen/TargetInfo.h>
5049
#include <CodeGen/CGCall.h>
5150
#include <CodeGen/CGCXXABI.h>
@@ -3278,9 +3277,8 @@ bool Parser::IsValidDeclaration(const clang::SourceLocation& Loc)
32783277

32793278
//-----------------------------------//
32803279

3281-
void Parser::WalkAST()
3280+
void Parser::WalkAST(clang::TranslationUnitDecl* TU)
32823281
{
3283-
auto TU = c->getASTContext().getTranslationUnitDecl();
32843282
for (auto D : TU->decls())
32853283
{
32863284
if (D->getBeginLoc().isValid() &&
@@ -4049,107 +4047,130 @@ void Parser::HandleDiagnostics(ParserResult* res)
40494047
}
40504048
}
40514049

4052-
ParserResult* Parser::ParseHeader(const std::vector<std::string>& SourceFiles)
4050+
void Parser::SetupLLVMCodegen()
40534051
{
4054-
assert(opts->ASTContext && "Expected a valid ASTContext");
4055-
4056-
auto res = new ParserResult();
4057-
4058-
if (SourceFiles.empty())
4059-
{
4060-
res->kind = ParserResultKind::FileNotFound;
4061-
return res;
4062-
}
4052+
// Initialize enough Clang codegen machinery so we can get at ABI details.
4053+
LLVMModule.reset(new llvm::Module("", LLVMCtx));
40634054

4064-
Setup();
4055+
LLVMModule->setTargetTriple(c->getTarget().getTriple().getTriple());
4056+
LLVMModule->setDataLayout(c->getTarget().getDataLayout());
40654057

4066-
std::unique_ptr<clang::SemaConsumer> SC(new clang::SemaConsumer());
4067-
c->setASTConsumer(std::move(SC));
4058+
CGM.reset(new clang::CodeGen::CodeGenModule(c->getASTContext(),
4059+
c->getHeaderSearchOpts(), c->getPreprocessorOpts(),
4060+
c->getCodeGenOpts(), *LLVMModule, c->getDiagnostics()));
40684061

4069-
c->createSema(clang::TU_Complete, 0);
4062+
CGT.reset(new clang::CodeGen::CodeGenTypes(*CGM.get()));
40704063

4071-
auto DiagClient = new DiagnosticConsumer();
4072-
c->getDiagnostics().setClient(DiagClient);
4064+
codeGenTypes = CGT.get();
4065+
}
40734066

4067+
bool Parser::SetupSourceFiles(const std::vector<std::string>& SourceFiles,
4068+
std::vector<const clang::FileEntry*>& FileEntries)
4069+
{
40744070
// Check that the file is reachable.
40754071
const clang::DirectoryLookup *Dir;
40764072
llvm::SmallVector<
40774073
std::pair<const clang::FileEntry *, const clang::DirectoryEntry *>,
40784074
0> Includers;
40794075

4080-
std::vector<const clang::FileEntry*> FileEntries;
40814076
for (const auto& SourceFile : SourceFiles)
40824077
{
40834078
auto FileEntry = c->getPreprocessor().getHeaderSearchInfo().LookupFile(SourceFile,
40844079
clang::SourceLocation(), /*isAngled*/true,
40854080
nullptr, Dir, Includers, nullptr, nullptr, nullptr, nullptr, nullptr);
40864081

40874082
if (!FileEntry)
4088-
{
4089-
res->kind = ParserResultKind::FileNotFound;
4090-
return res;
4091-
}
4083+
return false;
4084+
40924085
FileEntries.push_back(FileEntry);
40934086
}
40944087

40954088
// Create a virtual file that includes the header. This gets rid of some
40964089
// Clang warnings about parsing an header file as the main file.
40974090

4098-
std::string str;
4091+
std::string source;
40994092
for (const auto& SourceFile : SourceFiles)
41004093
{
4101-
str += "#include \"" + SourceFile + "\"" + "\n";
4094+
source += "#include \"" + SourceFile + "\"" + "\n";
41024095
}
4103-
str += "\0";
4096+
source += "\0";
41044097

4105-
auto buffer = llvm::MemoryBuffer::getMemBuffer(str);
4098+
auto buffer = llvm::MemoryBuffer::getMemBufferCopy(source);
41064099
auto& SM = c->getSourceManager();
41074100
SM.setMainFileID(SM.createFileID(std::move(buffer)));
41084101

4109-
clang::DiagnosticConsumer* client = c->getDiagnostics().getClient();
4110-
client->BeginSourceFile(c->getLangOpts(), &c->getPreprocessor());
4102+
return true;
4103+
}
41114104

4112-
ParseAST(c->getSema());
4105+
class SemaConsumer : public clang::SemaConsumer {
4106+
CppSharp::CppParser::Parser& Parser;
4107+
std::vector<const clang::FileEntry*>& FileEntries;
4108+
public:
4109+
SemaConsumer(CppSharp::CppParser::Parser& parser,
4110+
std::vector<const clang::FileEntry*>& entries)
4111+
: Parser(parser), FileEntries(entries) {}
4112+
virtual void HandleTranslationUnit(clang::ASTContext& Ctx) override;
4113+
};
41134114

4114-
client->EndSourceFile();
4115+
void SemaConsumer::HandleTranslationUnit(clang::ASTContext& Ctx)
4116+
{
4117+
auto FileEntry = FileEntries[0];
4118+
auto FileName = FileEntry->getName();
4119+
auto Unit = Parser.opts->ASTContext->FindOrCreateModule(FileName);
41154120

4116-
HandleDiagnostics(res);
4121+
auto TU = Ctx.getTranslationUnitDecl();
4122+
Parser.HandleDeclaration(TU, Unit);
41174123

4118-
if(client->getNumErrors() != 0)
4124+
if (Unit->originalPtr == nullptr)
4125+
Unit->originalPtr = (void*)FileEntry;
4126+
4127+
Parser.WalkAST(TU);
4128+
}
4129+
4130+
ParserResult* Parser::ParseHeader(const std::vector<std::string>& SourceFiles)
4131+
{
4132+
assert(opts->ASTContext && "Expected a valid ASTContext");
4133+
4134+
auto res = new ParserResult();
4135+
4136+
if (SourceFiles.empty())
41194137
{
4120-
res->kind = ParserResultKind::Error;
4138+
res->kind = ParserResultKind::FileNotFound;
41214139
return res;
41224140
}
41234141

4124-
auto& AST = c->getASTContext();
4142+
Setup();
4143+
SetupLLVMCodegen();
41254144

4126-
auto FileEntry = FileEntries[0];
4127-
auto FileName = FileEntry->getName();
4128-
auto Unit = opts->ASTContext->FindOrCreateModule(FileName);
4145+
std::vector<const clang::FileEntry*> FileEntries;
4146+
if (!SetupSourceFiles(SourceFiles, FileEntries))
4147+
{
4148+
res->kind = ParserResultKind::FileNotFound;
4149+
return res;
4150+
}
41294151

4130-
auto TU = AST.getTranslationUnitDecl();
4131-
HandleDeclaration(TU, Unit);
4152+
std::unique_ptr<SemaConsumer> SC(new SemaConsumer(*this, FileEntries));
4153+
c->setASTConsumer(std::move(SC));
41324154

4133-
if (Unit->originalPtr == nullptr)
4134-
Unit->originalPtr = (void*)FileEntry;
4155+
c->createSema(clang::TU_Complete, 0);
41354156

4136-
// Initialize enough Clang codegen machinery so we can get at ABI details.
4137-
llvm::LLVMContext Ctx;
4138-
std::unique_ptr<llvm::Module> M(new llvm::Module("", Ctx));
4157+
auto DiagClient = new DiagnosticConsumer();
4158+
c->getDiagnostics().setClient(DiagClient);
41394159

4140-
M->setTargetTriple(c->getTarget().getTriple().getTriple());
4141-
M->setDataLayout(c->getTarget().getDataLayout());
4160+
clang::DiagnosticConsumer* client = c->getDiagnostics().getClient();
4161+
client->BeginSourceFile(c->getLangOpts(), &c->getPreprocessor());
41424162

4143-
std::unique_ptr<clang::CodeGen::CodeGenModule> CGM(
4144-
new clang::CodeGen::CodeGenModule(c->getASTContext(), c->getHeaderSearchOpts(),
4145-
c->getPreprocessorOpts(), c->getCodeGenOpts(), *M, c->getDiagnostics()));
4163+
ParseAST(c->getSema());
41464164

4147-
std::unique_ptr<clang::CodeGen::CodeGenTypes> CGT(
4148-
new clang::CodeGen::CodeGenTypes(*CGM.get()));
4165+
client->EndSourceFile();
41494166

4150-
codeGenTypes = CGT.get();
4167+
HandleDiagnostics(res);
41514168

4152-
WalkAST();
4169+
if(client->getNumErrors() != 0)
4170+
{
4171+
res->kind = ParserResultKind::Error;
4172+
return res;
4173+
}
41534174

41544175
res->targetInfo = GetTargetInfo();
41554176

src/CppParser/Parser.h

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
#include <clang/Frontend/CompilerInstance.h>
1919
#include <clang/Sema/Scope.h>
2020

21+
#include <CodeGen/CodeGenModule.h>
22+
#include <CodeGen/CodeGenTypes.h>
23+
2124
#include "CXXABI.h"
2225
#include "CppParser.h"
2326

@@ -53,11 +56,19 @@ class Parser
5356
ParserResult* ParseHeader(const std::vector<std::string>& SourceFiles);
5457
ParserResult* ParseLibrary(const std::string& File);
5558

59+
void WalkAST(clang::TranslationUnitDecl* TU);
60+
void HandleDeclaration(const clang::Decl* D, Declaration* Decl);
61+
CppParserOptions* opts;
62+
5663
private:
64+
65+
void SetupLLVMCodegen();
66+
bool SetupSourceFiles(const std::vector<std::string>& SourceFiles,
67+
std::vector<const clang::FileEntry*>& FileEntries);
68+
5769
bool IsSupported(const clang::NamedDecl* ND);
5870
bool IsSupported(const clang::CXXMethodDecl* MD);
5971
// AST traversers
60-
void WalkAST();
6172
Declaration* WalkDeclaration(const clang::Decl* D);
6273
Declaration* WalkDeclarationDef(clang::Decl* D);
6374
Enumeration* WalkEnum(const clang::EnumDecl* ED);
@@ -137,7 +148,6 @@ class Parser
137148
DeclarationContext* GetNamespace(const clang::Decl* D, const clang::DeclContext* Ctx);
138149
DeclarationContext* GetNamespace(const clang::Decl* D);
139150

140-
void HandleDeclaration(const clang::Decl* D, Declaration* Decl);
141151
void HandleOriginalText(const clang::Decl* D, Declaration* Decl);
142152
void HandleComments(const clang::Decl* D, Declaration* Decl);
143153
void HandleDiagnostics(ParserResult* res);
@@ -154,9 +164,12 @@ class Parser
154164
ParserTargetInfo* GetTargetInfo();
155165

156166
int index;
157-
CppParserOptions* opts;
158167
std::unique_ptr<clang::CompilerInstance> c;
159168
clang::TargetCXXABI::Kind targetABI;
169+
llvm::LLVMContext LLVMCtx;
170+
std::unique_ptr<llvm::Module> LLVMModule;
171+
std::unique_ptr<clang::CodeGen::CodeGenModule> CGM;
172+
std::unique_ptr<clang::CodeGen::CodeGenTypes> CGT;
160173
clang::CodeGen::CodeGenTypes* codeGenTypes;
161174
std::unordered_map<const clang::TemplateTypeParmDecl*, TypeTemplateParameter*> walkedTypeTemplateParameters;
162175
std::unordered_map<const clang::TemplateTemplateParmDecl*, TemplateTemplateParameter*> walkedTemplateTemplateParameters;

tests/Common/Common.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1433,3 +1433,27 @@ enum ItemsDifferByCase
14331433
Case_a,
14341434
Case_A
14351435
};
1436+
1437+
template <typename T> struct MyListBase
1438+
{
1439+
protected:
1440+
~MyListBase() {}
1441+
};
1442+
1443+
template <typename T>
1444+
class MyList : public MyListBase<T>
1445+
{
1446+
public:
1447+
inline MyList() { }
1448+
};
1449+
1450+
template <> struct MyListBase<int>
1451+
{
1452+
};
1453+
1454+
class MyIntList : public MyList<int>
1455+
{
1456+
inline MyIntList(MyList<int> &&l) { }
1457+
};
1458+
1459+
void MyFunc(MyList<void *> *list);

0 commit comments

Comments
 (0)