mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-12-23 16:06:24 +00:00
Support non-identifier module names when preprocessing modules.
llvm-svn: 305758
This commit is contained in:
parent
8361b0a9bb
commit
9565c75b29
@ -393,7 +393,9 @@ public:
|
||||
|
||||
/// \brief Retrieve the full name of this module, including the path from
|
||||
/// its top-level module.
|
||||
std::string getFullModuleName() const;
|
||||
/// \param AllowStringLiterals If \c true, components that might not be
|
||||
/// lexically valid as identifiers will be emitted as string literals.
|
||||
std::string getFullModuleName(bool AllowStringLiterals = false) const;
|
||||
|
||||
/// \brief Whether the full name of this module is equal to joining
|
||||
/// \p nameParts with "."s.
|
||||
|
@ -13,6 +13,7 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Basic/Module.h"
|
||||
#include "clang/Basic/CharInfo.h"
|
||||
#include "clang/Basic/FileManager.h"
|
||||
#include "clang/Basic/LangOptions.h"
|
||||
#include "clang/Basic/TargetInfo.h"
|
||||
@ -125,7 +126,36 @@ const Module *Module::getTopLevelModule() const {
|
||||
return Result;
|
||||
}
|
||||
|
||||
std::string Module::getFullModuleName() const {
|
||||
static StringRef getModuleNameFromComponent(
|
||||
const std::pair<std::string, SourceLocation> &IdComponent) {
|
||||
return IdComponent.first;
|
||||
}
|
||||
static StringRef getModuleNameFromComponent(StringRef R) { return R; }
|
||||
|
||||
template<typename InputIter>
|
||||
static void printModuleId(raw_ostream &OS, InputIter Begin, InputIter End,
|
||||
bool AllowStringLiterals = true) {
|
||||
for (InputIter It = Begin; It != End; ++It) {
|
||||
if (It != Begin)
|
||||
OS << ".";
|
||||
|
||||
StringRef Name = getModuleNameFromComponent(*It);
|
||||
if (!AllowStringLiterals || isValidIdentifier(Name))
|
||||
OS << Name;
|
||||
else {
|
||||
OS << '"';
|
||||
OS.write_escaped(Name);
|
||||
OS << '"';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Container>
|
||||
static void printModuleId(raw_ostream &OS, const Container &C) {
|
||||
return printModuleId(OS, C.begin(), C.end());
|
||||
}
|
||||
|
||||
std::string Module::getFullModuleName(bool AllowStringLiterals) const {
|
||||
SmallVector<StringRef, 2> Names;
|
||||
|
||||
// Build up the set of module names (from innermost to outermost).
|
||||
@ -133,14 +163,10 @@ std::string Module::getFullModuleName() const {
|
||||
Names.push_back(M->Name);
|
||||
|
||||
std::string Result;
|
||||
for (SmallVectorImpl<StringRef>::reverse_iterator I = Names.rbegin(),
|
||||
IEnd = Names.rend();
|
||||
I != IEnd; ++I) {
|
||||
if (!Result.empty())
|
||||
Result += '.';
|
||||
|
||||
Result += *I;
|
||||
}
|
||||
llvm::raw_string_ostream Out(Result);
|
||||
printModuleId(Out, Names.rbegin(), Names.rend(), AllowStringLiterals);
|
||||
Out.flush();
|
||||
|
||||
return Result;
|
||||
}
|
||||
@ -240,14 +266,6 @@ Module *Module::findSubmodule(StringRef Name) const {
|
||||
return SubModules[Pos->getValue()];
|
||||
}
|
||||
|
||||
static void printModuleId(raw_ostream &OS, const ModuleId &Id) {
|
||||
for (unsigned I = 0, N = Id.size(); I != N; ++I) {
|
||||
if (I)
|
||||
OS << ".";
|
||||
OS << Id[I].first;
|
||||
}
|
||||
}
|
||||
|
||||
void Module::getExportedModules(SmallVectorImpl<Module *> &Exported) const {
|
||||
// All non-explicit submodules are exported.
|
||||
for (std::vector<Module *>::const_iterator I = SubModules.begin(),
|
||||
@ -334,7 +352,8 @@ void Module::print(raw_ostream &OS, unsigned Indent) const {
|
||||
OS << "framework ";
|
||||
if (IsExplicit)
|
||||
OS << "explicit ";
|
||||
OS << "module " << Name;
|
||||
OS << "module ";
|
||||
printModuleId(OS, &Name, &Name + 1);
|
||||
|
||||
if (IsSystem || IsExternC) {
|
||||
OS.indent(Indent + 2);
|
||||
@ -434,7 +453,7 @@ void Module::print(raw_ostream &OS, unsigned Indent) const {
|
||||
OS.indent(Indent + 2);
|
||||
OS << "export ";
|
||||
if (Module *Restriction = Exports[I].getPointer()) {
|
||||
OS << Restriction->getFullModuleName();
|
||||
OS << Restriction->getFullModuleName(true);
|
||||
if (Exports[I].getInt())
|
||||
OS << ".*";
|
||||
} else {
|
||||
@ -455,7 +474,7 @@ void Module::print(raw_ostream &OS, unsigned Indent) const {
|
||||
for (unsigned I = 0, N = DirectUses.size(); I != N; ++I) {
|
||||
OS.indent(Indent + 2);
|
||||
OS << "use ";
|
||||
OS << DirectUses[I]->getFullModuleName();
|
||||
OS << DirectUses[I]->getFullModuleName(true);
|
||||
OS << "\n";
|
||||
}
|
||||
|
||||
@ -488,7 +507,7 @@ void Module::print(raw_ostream &OS, unsigned Indent) const {
|
||||
for (unsigned I = 0, N = Conflicts.size(); I != N; ++I) {
|
||||
OS.indent(Indent + 2);
|
||||
OS << "conflict ";
|
||||
OS << Conflicts[I].Other->getFullModuleName();
|
||||
OS << Conflicts[I].Other->getFullModuleName(true);
|
||||
OS << ", \"";
|
||||
OS.write_escaped(Conflicts[I].Message);
|
||||
OS << "\"\n";
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "clang/AST/ASTConsumer.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/Basic/CharInfo.h"
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "clang/Basic/FileManager.h"
|
||||
#include "clang/Basic/MemoryBufferCache.h"
|
||||
@ -1902,17 +1903,23 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
|
||||
void CompilerInstance::loadModuleFromSource(SourceLocation ImportLoc,
|
||||
StringRef ModuleName,
|
||||
StringRef Source) {
|
||||
// Avoid creating filenames with special characters.
|
||||
SmallString<128> CleanModuleName(ModuleName);
|
||||
for (auto &C : CleanModuleName)
|
||||
if (!isAlphanumeric(C))
|
||||
C = '_';
|
||||
|
||||
// FIXME: Using a randomized filename here means that our intermediate .pcm
|
||||
// output is nondeterministic (as .pcm files refer to each other by name).
|
||||
// Can this affect the output in any way?
|
||||
SmallString<128> ModuleFileName;
|
||||
if (std::error_code EC = llvm::sys::fs::createTemporaryFile(
|
||||
ModuleName, "pcm", ModuleFileName)) {
|
||||
CleanModuleName, "pcm", ModuleFileName)) {
|
||||
getDiagnostics().Report(ImportLoc, diag::err_fe_unable_to_open_output)
|
||||
<< ModuleFileName << EC.message();
|
||||
return;
|
||||
}
|
||||
std::string ModuleMapFileName = (ModuleName + ".map").str();
|
||||
std::string ModuleMapFileName = (CleanModuleName + ".map").str();
|
||||
|
||||
FrontendInputFile Input(
|
||||
ModuleMapFileName,
|
||||
|
@ -349,7 +349,7 @@ void PrintPPOutputPPCallbacks::InclusionDirective(SourceLocation HashLoc,
|
||||
case tok::pp_include_next:
|
||||
startNewLineIfNeeded();
|
||||
MoveToLine(HashLoc);
|
||||
OS << "#pragma clang module import " << Imported->getFullModuleName()
|
||||
OS << "#pragma clang module import " << Imported->getFullModuleName(true)
|
||||
<< " /* clang -E: implicit import for "
|
||||
<< "#" << PP.getSpelling(IncludeTok) << " "
|
||||
<< (IsAngled ? '<' : '"') << FileName << (IsAngled ? '>' : '"')
|
||||
@ -378,14 +378,14 @@ void PrintPPOutputPPCallbacks::InclusionDirective(SourceLocation HashLoc,
|
||||
/// Handle entering the scope of a module during a module compilation.
|
||||
void PrintPPOutputPPCallbacks::BeginModule(const Module *M) {
|
||||
startNewLineIfNeeded();
|
||||
OS << "#pragma clang module begin " << M->getFullModuleName();
|
||||
OS << "#pragma clang module begin " << M->getFullModuleName(true);
|
||||
setEmittedDirectiveOnThisLine();
|
||||
}
|
||||
|
||||
/// Handle leaving the scope of a module during a module compilation.
|
||||
void PrintPPOutputPPCallbacks::EndModule(const Module *M) {
|
||||
startNewLineIfNeeded();
|
||||
OS << "#pragma clang module end /*" << M->getFullModuleName() << "*/";
|
||||
OS << "#pragma clang module end /*" << M->getFullModuleName(true) << "*/";
|
||||
setEmittedDirectiveOnThisLine();
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include "clang/Rewrite/Frontend/FrontendActions.h"
|
||||
#include "clang/AST/ASTConsumer.h"
|
||||
#include "clang/Basic/CharInfo.h"
|
||||
#include "clang/Frontend/CompilerInstance.h"
|
||||
#include "clang/Frontend/FrontendActions.h"
|
||||
#include "clang/Frontend/FrontendDiagnostic.h"
|
||||
@ -224,7 +225,15 @@ public:
|
||||
auto OS = Out.lock();
|
||||
assert(OS && "loaded module file after finishing rewrite action?");
|
||||
|
||||
(*OS) << "#pragma clang module build " << MF->ModuleName << "\n";
|
||||
(*OS) << "#pragma clang module build ";
|
||||
if (isValidIdentifier(MF->ModuleName))
|
||||
(*OS) << MF->ModuleName;
|
||||
else {
|
||||
(*OS) << '"';
|
||||
OS->write_escaped(MF->ModuleName);
|
||||
(*OS) << '"';
|
||||
}
|
||||
(*OS) << '\n';
|
||||
|
||||
// Rewrite the contents of the module in a separate compiler instance.
|
||||
CompilerInstance Instance(CI.getPCHContainerOperations(),
|
||||
|
@ -140,7 +140,7 @@ void InclusionRewriter::WriteLineInfo(StringRef Filename, int Line,
|
||||
}
|
||||
|
||||
void InclusionRewriter::WriteImplicitModuleImport(const Module *Mod) {
|
||||
OS << "#pragma clang module import " << Mod->getFullModuleName()
|
||||
OS << "#pragma clang module import " << Mod->getFullModuleName(true)
|
||||
<< " /* clang -frewrite-includes: implicit import */" << MainEOL;
|
||||
}
|
||||
|
||||
@ -471,15 +471,15 @@ void InclusionRewriter::Process(FileID FileId,
|
||||
else if (const IncludedFile *Inc = FindIncludeAtLocation(Loc)) {
|
||||
const Module *Mod = FindEnteredModule(Loc);
|
||||
if (Mod)
|
||||
OS << "#pragma clang module begin " << Mod->getFullModuleName()
|
||||
<< "\n";
|
||||
OS << "#pragma clang module begin "
|
||||
<< Mod->getFullModuleName(true) << "\n";
|
||||
|
||||
// Include and recursively process the file.
|
||||
Process(Inc->Id, Inc->FileType);
|
||||
|
||||
if (Mod)
|
||||
OS << "#pragma clang module end /*" << Mod->getFullModuleName()
|
||||
<< "*/\n";
|
||||
OS << "#pragma clang module end /*"
|
||||
<< Mod->getFullModuleName(true) << "*/\n";
|
||||
|
||||
// Add line marker to indicate we're returning from an included
|
||||
// file.
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "clang/Basic/TokenKinds.h"
|
||||
#include "clang/Lex/HeaderSearch.h"
|
||||
#include "clang/Lex/LexDiagnostic.h"
|
||||
#include "clang/Lex/LiteralSupport.h"
|
||||
#include "clang/Lex/MacroInfo.h"
|
||||
#include "clang/Lex/PPCallbacks.h"
|
||||
#include "clang/Lex/Preprocessor.h"
|
||||
@ -754,15 +755,52 @@ void Preprocessor::HandlePragmaIncludeAlias(Token &Tok) {
|
||||
getHeaderSearchInfo().AddIncludeAlias(OriginalSource, ReplaceFileName);
|
||||
}
|
||||
|
||||
// Lex a component of a module name: either an identifier or a string literal;
|
||||
// for components that can be expressed both ways, the two forms are equivalent.
|
||||
static bool LexModuleNameComponent(
|
||||
Preprocessor &PP, Token &Tok,
|
||||
std::pair<IdentifierInfo *, SourceLocation> &ModuleNameComponent,
|
||||
bool First) {
|
||||
PP.LexUnexpandedToken(Tok);
|
||||
if (Tok.is(tok::string_literal) && !Tok.hasUDSuffix()) {
|
||||
StringLiteralParser Literal(Tok, PP);
|
||||
if (Literal.hadError)
|
||||
return true;
|
||||
ModuleNameComponent = std::make_pair(
|
||||
PP.getIdentifierInfo(Literal.GetString()), Tok.getLocation());
|
||||
} else if (!Tok.isAnnotation() && Tok.getIdentifierInfo()) {
|
||||
ModuleNameComponent =
|
||||
std::make_pair(Tok.getIdentifierInfo(), Tok.getLocation());
|
||||
} else {
|
||||
PP.Diag(Tok.getLocation(), diag::err_pp_expected_module_name) << First;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool LexModuleName(
|
||||
Preprocessor &PP, Token &Tok,
|
||||
llvm::SmallVectorImpl<std::pair<IdentifierInfo *, SourceLocation>>
|
||||
&ModuleName) {
|
||||
while (true) {
|
||||
std::pair<IdentifierInfo*, SourceLocation> NameComponent;
|
||||
if (LexModuleNameComponent(PP, Tok, NameComponent, ModuleName.empty()))
|
||||
return true;
|
||||
ModuleName.push_back(NameComponent);
|
||||
|
||||
PP.LexUnexpandedToken(Tok);
|
||||
if (Tok.isNot(tok::period))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void Preprocessor::HandlePragmaModuleBuild(Token &Tok) {
|
||||
SourceLocation Loc = Tok.getLocation();
|
||||
|
||||
LexUnexpandedToken(Tok);
|
||||
if (Tok.isAnnotation() || !Tok.getIdentifierInfo()) {
|
||||
Diag(Tok.getLocation(), diag::err_pp_expected_module_name) << true;
|
||||
std::pair<IdentifierInfo *, SourceLocation> ModuleNameLoc;
|
||||
if (LexModuleNameComponent(*this, Tok, ModuleNameLoc, true))
|
||||
return;
|
||||
}
|
||||
IdentifierInfo *ModuleName = Tok.getIdentifierInfo();
|
||||
IdentifierInfo *ModuleName = ModuleNameLoc.first;
|
||||
|
||||
LexUnexpandedToken(Tok);
|
||||
if (Tok.isNot(tok::eod)) {
|
||||
@ -1383,26 +1421,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
static bool LexModuleName(
|
||||
Preprocessor &PP, Token &Tok,
|
||||
llvm::SmallVectorImpl<std::pair<IdentifierInfo *, SourceLocation>>
|
||||
&ModuleName) {
|
||||
while (true) {
|
||||
PP.LexUnexpandedToken(Tok);
|
||||
if (Tok.isAnnotation() || !Tok.getIdentifierInfo()) {
|
||||
PP.Diag(Tok.getLocation(), diag::err_pp_expected_module_name)
|
||||
<< ModuleName.empty();
|
||||
return true;
|
||||
}
|
||||
|
||||
ModuleName.emplace_back(Tok.getIdentifierInfo(), Tok.getLocation());
|
||||
|
||||
PP.LexUnexpandedToken(Tok);
|
||||
if (Tok.isNot(tok::period))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Handle the clang \#pragma module import extension. The syntax is:
|
||||
/// \code
|
||||
/// #pragma clang module import some.module.name
|
||||
@ -1473,7 +1491,7 @@ struct PragmaModuleBeginHandler : public PragmaHandler {
|
||||
// be loaded or implicitly loadable.
|
||||
// FIXME: We could create the submodule here. We'd need to know whether
|
||||
// it's supposed to be explicit, but not much else.
|
||||
Module *M = PP.getHeaderSearchInfo().getModuleMap().findModule(Current);
|
||||
Module *M = PP.getHeaderSearchInfo().lookupModule(Current);
|
||||
if (!M) {
|
||||
PP.Diag(ModuleName.front().second,
|
||||
diag::err_pp_module_begin_no_module_map) << Current;
|
||||
|
@ -1,6 +1,10 @@
|
||||
// RUN: rm -rf %t
|
||||
// RUN: %clang_cc1 -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -fmodules-decluse -I %S/Inputs/string_names %s -fmodule-name="my/module-a" -verify
|
||||
|
||||
// Check that we can preprocess with string module names.
|
||||
// RUN: %clang_cc1 -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -I %S/Inputs/string_names %s -fmodule-name="my/module-a" -E -frewrite-imports -o %t/test.ii
|
||||
// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-decluse -I %S/Inputs/string_names %t/test.ii -fmodule-name="my/module-a"
|
||||
|
||||
#include "a.h"
|
||||
#include "b.h" // expected-error {{does not depend on a module exporting}}
|
||||
#include "c.h"
|
||||
|
Loading…
Reference in New Issue
Block a user