forked from OSchip/llvm-project
Add #pragma clang module begin/end pragmas and generate them when preprocessing a module.
These pragmas are intended to simulate the effect of entering or leaving a file with an associated module. This is not completely implemented yet: declarations between the pragmas will not be attributed to the correct module, but macro visibility is already functional. Modules named by #pragma clang module begin must already be known to clang (in some module map that's either loaded or on the search path). llvm-svn: 302098
This commit is contained in:
parent
8e23870585
commit
d13863008b
|
@ -475,8 +475,6 @@ def warn_pragma_pop_macro_no_push : Warning<
|
|||
def warn_pragma_message : Warning<"%0">,
|
||||
InGroup<PoundPragmaMessage>, DefaultWarnNoWerror;
|
||||
def err_pragma_message : Error<"%0">;
|
||||
def err_pragma_module_import_expected_module_name : Error<
|
||||
"expected %select{identifier in|'.' or end of directive after}0 module name">;
|
||||
def warn_pragma_ignored : Warning<"unknown pragma ignored">,
|
||||
InGroup<UnknownPragmas>, DefaultIgnore;
|
||||
def ext_stdc_pragma_ignored : ExtWarn<"unknown pragma in STDC namespace">,
|
||||
|
@ -511,6 +509,22 @@ def warn_pragma_debug_unexpected_command : Warning<
|
|||
"unexpected debug command '%0'">, InGroup<IgnoredPragmas>;
|
||||
def warn_pragma_debug_missing_argument : Warning<
|
||||
"missing argument to debug command '%0'">, InGroup<IgnoredPragmas>;
|
||||
// #pragma module
|
||||
def err_pp_expected_module_name : Error<
|
||||
"expected %select{identifier after '.' in |}0module name">;
|
||||
def err_pp_module_begin_wrong_module : Error<
|
||||
"must specify '-fmodule-name=%0' to enter %select{|submodule of }1"
|
||||
"this module%select{ (current module is %3)|}2">;
|
||||
def err_pp_module_begin_no_module_map : Error<
|
||||
"no module map available for module %0">;
|
||||
def err_pp_module_begin_no_submodule : Error<
|
||||
"submodule %0.%1 not declared in module map">;
|
||||
def err_pp_module_begin_without_module_end : Error<
|
||||
"no matching '#pragma clang module end' for this "
|
||||
"'#pragma clang module begin'">;
|
||||
def err_pp_module_end_without_module_begin : Error<
|
||||
"no matching '#pragma clang module begin' for this "
|
||||
"'#pragma clang module end'">;
|
||||
|
||||
def err_defined_macro_name : Error<"'defined' cannot be used as a macro name">;
|
||||
def err_paste_at_start : Error<
|
||||
|
|
|
@ -324,7 +324,7 @@ class Preprocessor {
|
|||
|
||||
/// \brief If the current lexer is for a submodule that is being built, this
|
||||
/// is that submodule.
|
||||
Module *CurSubmodule;
|
||||
Module *CurLexerSubmodule;
|
||||
|
||||
/// \brief Keeps track of the stack of files currently
|
||||
/// \#included, and macros currently being expanded from, not counting
|
||||
|
@ -507,16 +507,19 @@ class Preprocessor {
|
|||
|
||||
/// \brief Information about a submodule that we're currently building.
|
||||
struct BuildingSubmoduleInfo {
|
||||
BuildingSubmoduleInfo(Module *M, SourceLocation ImportLoc,
|
||||
BuildingSubmoduleInfo(Module *M, SourceLocation ImportLoc, bool IsPragma,
|
||||
SubmoduleState *OuterSubmoduleState,
|
||||
unsigned OuterPendingModuleMacroNames)
|
||||
: M(M), ImportLoc(ImportLoc), OuterSubmoduleState(OuterSubmoduleState),
|
||||
: M(M), ImportLoc(ImportLoc), IsPragma(IsPragma),
|
||||
OuterSubmoduleState(OuterSubmoduleState),
|
||||
OuterPendingModuleMacroNames(OuterPendingModuleMacroNames) {}
|
||||
|
||||
/// The module that we are building.
|
||||
Module *M;
|
||||
/// The location at which the module was included.
|
||||
SourceLocation ImportLoc;
|
||||
/// Whether we entered this submodule via a pragma.
|
||||
bool IsPragma;
|
||||
/// The previous SubmoduleState.
|
||||
SubmoduleState *OuterSubmoduleState;
|
||||
/// The number of pending module macro names when we started building this.
|
||||
|
@ -773,8 +776,9 @@ public:
|
|||
/// expansions going on at the time.
|
||||
PreprocessorLexer *getCurrentFileLexer() const;
|
||||
|
||||
/// \brief Return the submodule owning the file being lexed.
|
||||
Module *getCurrentSubmodule() const { return CurSubmodule; }
|
||||
/// \brief Return the submodule owning the file being lexed. This may not be
|
||||
/// the current module if we have changed modules since entering the file.
|
||||
Module *getCurrentLexerSubmodule() const { return CurLexerSubmodule; }
|
||||
|
||||
/// \brief Returns the FileID for the preprocessor predefines.
|
||||
FileID getPredefinesFileID() const { return PredefinesFileID; }
|
||||
|
@ -1726,13 +1730,16 @@ public:
|
|||
bool CheckMacroName(Token &MacroNameTok, MacroUse isDefineUndef,
|
||||
bool *ShadowFlag = nullptr);
|
||||
|
||||
private:
|
||||
void EnterSubmodule(Module *M, SourceLocation ImportLoc, bool ForPragma);
|
||||
Module *LeaveSubmodule(bool ForPragma);
|
||||
|
||||
private:
|
||||
void PushIncludeMacroStack() {
|
||||
assert(CurLexerKind != CLK_CachingLexer && "cannot push a caching lexer");
|
||||
IncludeMacroStack.emplace_back(
|
||||
CurLexerKind, CurSubmodule, std::move(CurLexer), std::move(CurPTHLexer),
|
||||
CurPPLexer, std::move(CurTokenLexer), CurDirLookup);
|
||||
IncludeMacroStack.emplace_back(CurLexerKind, CurLexerSubmodule,
|
||||
std::move(CurLexer), std::move(CurPTHLexer),
|
||||
CurPPLexer, std::move(CurTokenLexer),
|
||||
CurDirLookup);
|
||||
CurPPLexer = nullptr;
|
||||
}
|
||||
|
||||
|
@ -1742,16 +1749,13 @@ private:
|
|||
CurPPLexer = IncludeMacroStack.back().ThePPLexer;
|
||||
CurTokenLexer = std::move(IncludeMacroStack.back().TheTokenLexer);
|
||||
CurDirLookup = IncludeMacroStack.back().TheDirLookup;
|
||||
CurSubmodule = IncludeMacroStack.back().TheSubmodule;
|
||||
CurLexerSubmodule = IncludeMacroStack.back().TheSubmodule;
|
||||
CurLexerKind = IncludeMacroStack.back().CurLexerKind;
|
||||
IncludeMacroStack.pop_back();
|
||||
}
|
||||
|
||||
void PropagateLineStartLeadingSpaceInfo(Token &Result);
|
||||
|
||||
void EnterSubmodule(Module *M, SourceLocation ImportLoc);
|
||||
void LeaveSubmodule();
|
||||
|
||||
/// Determine whether we need to create module macros for #defines in the
|
||||
/// current context.
|
||||
bool needModuleMacros() const;
|
||||
|
@ -1967,7 +1971,6 @@ public:
|
|||
void HandlePragmaPoison();
|
||||
void HandlePragmaSystemHeader(Token &SysHeaderTok);
|
||||
void HandlePragmaDependency(Token &DependencyTok);
|
||||
void HandlePragmaModuleImport(Token &Tok);
|
||||
void HandlePragmaPushMacro(Token &Tok);
|
||||
void HandlePragmaPopMacro(Token &Tok);
|
||||
void HandlePragmaIncludeAlias(Token &Tok);
|
||||
|
|
|
@ -174,6 +174,9 @@ public:
|
|||
void MacroUndefined(const Token &MacroNameTok,
|
||||
const MacroDefinition &MD,
|
||||
const MacroDirective *Undef) override;
|
||||
|
||||
void BeginModule(const Module *M);
|
||||
void EndModule(const Module *M);
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
|
@ -372,6 +375,20 @@ 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();
|
||||
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() << "*/";
|
||||
setEmittedDirectiveOnThisLine();
|
||||
}
|
||||
|
||||
/// Ident - Handle #ident directives when read by the preprocessor.
|
||||
///
|
||||
void PrintPPOutputPPCallbacks::Ident(SourceLocation Loc, StringRef S) {
|
||||
|
@ -685,13 +702,27 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok,
|
|||
// -traditional-cpp the lexer keeps /all/ whitespace, including comments.
|
||||
SourceLocation StartLoc = Tok.getLocation();
|
||||
Callbacks->MoveToLine(StartLoc.getLocWithOffset(Tok.getLength()));
|
||||
} else if (Tok.is(tok::annot_module_include) ||
|
||||
Tok.is(tok::annot_module_begin) ||
|
||||
Tok.is(tok::annot_module_end)) {
|
||||
} else if (Tok.is(tok::annot_module_include)) {
|
||||
// PrintPPOutputPPCallbacks::InclusionDirective handles producing
|
||||
// appropriate output here. Ignore this token entirely.
|
||||
PP.Lex(Tok);
|
||||
continue;
|
||||
} else if (Tok.is(tok::annot_module_begin)) {
|
||||
// FIXME: We retrieve this token after the FileChanged callback, and
|
||||
// retrieve the module_end token before the FileChanged callback, so
|
||||
// we render this within the file and render the module end outside the
|
||||
// file, but this is backwards from the token locations: the module_begin
|
||||
// token is at the include location (outside the file) and the module_end
|
||||
// token is at the EOF location (within the file).
|
||||
Callbacks->BeginModule(
|
||||
reinterpret_cast<Module *>(Tok.getAnnotationValue()));
|
||||
PP.Lex(Tok);
|
||||
continue;
|
||||
} else if (Tok.is(tok::annot_module_end)) {
|
||||
Callbacks->EndModule(
|
||||
reinterpret_cast<Module *>(Tok.getAnnotationValue()));
|
||||
PP.Lex(Tok);
|
||||
continue;
|
||||
} else if (IdentifierInfo *II = Tok.getIdentifierInfo()) {
|
||||
OS << II->getName();
|
||||
} else if (Tok.isLiteral() && !Tok.needsCleaning() &&
|
||||
|
|
|
@ -46,6 +46,8 @@ class InclusionRewriter : public PPCallbacks {
|
|||
std::map<unsigned, IncludedFile> FileIncludes;
|
||||
/// Tracks where inclusions that import modules are found.
|
||||
std::map<unsigned, const Module *> ModuleIncludes;
|
||||
/// Tracks where inclusions that enter modules (in a module build) are found.
|
||||
std::map<unsigned, const Module *> ModuleEntryIncludes;
|
||||
/// Used transitively for building up the FileIncludes mapping over the
|
||||
/// various \c PPCallbacks callbacks.
|
||||
SourceLocation LastInclusionLocation;
|
||||
|
@ -57,6 +59,11 @@ public:
|
|||
PredefinesBuffer = Buf;
|
||||
}
|
||||
void detectMainFileEOL();
|
||||
void handleModuleBegin(Token &Tok) {
|
||||
assert(Tok.getKind() == tok::annot_module_begin);
|
||||
ModuleEntryIncludes.insert({Tok.getLocation().getRawEncoding(),
|
||||
(Module *)Tok.getAnnotationValue()});
|
||||
}
|
||||
private:
|
||||
void FileChanged(SourceLocation Loc, FileChangeReason Reason,
|
||||
SrcMgr::CharacteristicKind FileType,
|
||||
|
@ -84,6 +91,7 @@ private:
|
|||
bool &FileExists);
|
||||
const IncludedFile *FindIncludeAtLocation(SourceLocation Loc) const;
|
||||
const Module *FindModuleAtLocation(SourceLocation Loc) const;
|
||||
const Module *FindEnteredModule(SourceLocation Loc) const;
|
||||
StringRef NextIdentifierName(Lexer &RawLex, Token &RawToken);
|
||||
};
|
||||
|
||||
|
@ -211,6 +219,16 @@ InclusionRewriter::FindModuleAtLocation(SourceLocation Loc) const {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
/// Simple lookup for a SourceLocation (specifically one denoting the hash in
|
||||
/// an inclusion directive) in the map of module entry information.
|
||||
const Module *
|
||||
InclusionRewriter::FindEnteredModule(SourceLocation Loc) const {
|
||||
const auto I = ModuleEntryIncludes.find(Loc.getRawEncoding());
|
||||
if (I != ModuleEntryIncludes.end())
|
||||
return I->second;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// Detect the likely line ending style of \p FromFile by examining the first
|
||||
/// newline found within it.
|
||||
static StringRef DetectEOL(const MemoryBuffer &FromFile) {
|
||||
|
@ -452,8 +470,18 @@ void InclusionRewriter::Process(FileID FileId,
|
|||
if (const Module *Mod = FindModuleAtLocation(Loc))
|
||||
WriteImplicitModuleImport(Mod);
|
||||
else if (const IncludedFile *Inc = FindIncludeAtLocation(Loc)) {
|
||||
const Module *Mod = FindEnteredModule(Loc);
|
||||
if (Mod)
|
||||
OS << "#pragma clang module begin " << Mod->getFullModuleName()
|
||||
<< "\n";
|
||||
|
||||
// Include and recursively process the file.
|
||||
Process(Inc->Id, Inc->FileType);
|
||||
|
||||
if (Mod)
|
||||
OS << "#pragma clang module end /*" << Mod->getFullModuleName()
|
||||
<< "*/\n";
|
||||
|
||||
// Add line marker to indicate we're returning from an included
|
||||
// file.
|
||||
LineInfoExtra = " 2";
|
||||
|
@ -590,6 +618,8 @@ void clang::RewriteIncludesInInput(Preprocessor &PP, raw_ostream *OS,
|
|||
PP.SetMacroExpansionOnlyInDirectives();
|
||||
do {
|
||||
PP.Lex(Tok);
|
||||
if (Tok.is(tok::annot_module_begin))
|
||||
Rewrite->handleModuleBegin(Tok);
|
||||
} while (Tok.isNot(tok::eof));
|
||||
Rewrite->setPredefinesBuffer(SM.getBuffer(PP.getPredefinesFileID()));
|
||||
Rewrite->Process(PP.getPredefinesFileID(), SrcMgr::C_User);
|
||||
|
|
|
@ -2049,12 +2049,12 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
|
|||
M->getTopLevelModuleName() == getLangOpts().CurrentModule)
|
||||
return;
|
||||
|
||||
assert(!CurSubmodule && "should not have marked this as a module yet");
|
||||
CurSubmodule = M;
|
||||
assert(!CurLexerSubmodule && "should not have marked this as a module yet");
|
||||
CurLexerSubmodule = M;
|
||||
|
||||
// Let the macro handling code know that any future macros are within
|
||||
// the new submodule.
|
||||
EnterSubmodule(M, HashLoc);
|
||||
EnterSubmodule(M, HashLoc, /*ForPragma*/false);
|
||||
|
||||
// Let the parser know that any future declarations are within the new
|
||||
// submodule.
|
||||
|
@ -2082,7 +2082,7 @@ void Preprocessor::HandleIncludeNextDirective(SourceLocation HashLoc,
|
|||
} else if (isInPrimaryFile()) {
|
||||
Lookup = nullptr;
|
||||
Diag(IncludeNextTok, diag::pp_include_next_in_primary);
|
||||
} else if (CurSubmodule) {
|
||||
} else if (CurLexerSubmodule) {
|
||||
// Start looking up in the directory *after* the one in which the current
|
||||
// file would be found, if any.
|
||||
assert(CurPPLexer && "#include_next directive in macro?");
|
||||
|
|
|
@ -117,7 +117,7 @@ void Preprocessor::EnterSourceFileWithLexer(Lexer *TheLexer,
|
|||
CurLexer.reset(TheLexer);
|
||||
CurPPLexer = TheLexer;
|
||||
CurDirLookup = CurDir;
|
||||
CurSubmodule = nullptr;
|
||||
CurLexerSubmodule = nullptr;
|
||||
if (CurLexerKind != CLK_LexAfterModuleImport)
|
||||
CurLexerKind = CLK_Lexer;
|
||||
|
||||
|
@ -142,7 +142,7 @@ void Preprocessor::EnterSourceFileWithPTH(PTHLexer *PL,
|
|||
CurDirLookup = CurDir;
|
||||
CurPTHLexer.reset(PL);
|
||||
CurPPLexer = CurPTHLexer.get();
|
||||
CurSubmodule = nullptr;
|
||||
CurLexerSubmodule = nullptr;
|
||||
if (CurLexerKind != CLK_LexAfterModuleImport)
|
||||
CurLexerKind = CLK_PTHLexer;
|
||||
|
||||
|
@ -337,6 +337,26 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) {
|
|||
assert(!CurTokenLexer &&
|
||||
"Ending a file when currently in a macro!");
|
||||
|
||||
// If we have an unclosed module region from a pragma at the end of a
|
||||
// module, complain and close it now.
|
||||
// FIXME: This is not correct if we are building a module from PTH.
|
||||
const bool LeavingSubmodule = CurLexer && CurLexerSubmodule;
|
||||
if ((LeavingSubmodule || IncludeMacroStack.empty()) &&
|
||||
!BuildingSubmoduleStack.empty() &&
|
||||
BuildingSubmoduleStack.back().IsPragma) {
|
||||
Diag(BuildingSubmoduleStack.back().ImportLoc,
|
||||
diag::err_pp_module_begin_without_module_end);
|
||||
Module *M = LeaveSubmodule(/*ForPragma*/true);
|
||||
|
||||
Result.startToken();
|
||||
const char *EndPos = getCurLexerEndPos();
|
||||
CurLexer->BufferPtr = EndPos;
|
||||
CurLexer->FormTokenWithChars(Result, EndPos, tok::annot_module_end);
|
||||
Result.setAnnotationEndLoc(Result.getLocation());
|
||||
Result.setAnnotationValue(M);
|
||||
return true;
|
||||
}
|
||||
|
||||
// See if this file had a controlling macro.
|
||||
if (CurPPLexer) { // Not ending a macro, ignore it.
|
||||
if (const IdentifierInfo *ControllingMacro =
|
||||
|
@ -442,18 +462,17 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) {
|
|||
if (Callbacks && !isEndOfMacro && CurPPLexer)
|
||||
ExitedFID = CurPPLexer->getFileID();
|
||||
|
||||
bool LeavingSubmodule = CurSubmodule && CurLexer;
|
||||
if (LeavingSubmodule) {
|
||||
// We're done with this submodule.
|
||||
Module *M = LeaveSubmodule(/*ForPragma*/false);
|
||||
|
||||
// Notify the parser that we've left the module.
|
||||
const char *EndPos = getCurLexerEndPos();
|
||||
Result.startToken();
|
||||
CurLexer->BufferPtr = EndPos;
|
||||
CurLexer->FormTokenWithChars(Result, EndPos, tok::annot_module_end);
|
||||
Result.setAnnotationEndLoc(Result.getLocation());
|
||||
Result.setAnnotationValue(CurSubmodule);
|
||||
|
||||
// We're done with this submodule.
|
||||
LeaveSubmodule();
|
||||
Result.setAnnotationValue(M);
|
||||
}
|
||||
|
||||
// We're done with the #included file.
|
||||
|
@ -628,11 +647,13 @@ void Preprocessor::HandleMicrosoftCommentPaste(Token &Tok) {
|
|||
assert(!FoundLexer && "Lexer should return EOD before EOF in PP mode");
|
||||
}
|
||||
|
||||
void Preprocessor::EnterSubmodule(Module *M, SourceLocation ImportLoc) {
|
||||
void Preprocessor::EnterSubmodule(Module *M, SourceLocation ImportLoc,
|
||||
bool ForPragma) {
|
||||
if (!getLangOpts().ModulesLocalVisibility) {
|
||||
// Just track that we entered this submodule.
|
||||
BuildingSubmoduleStack.push_back(BuildingSubmoduleInfo(
|
||||
M, ImportLoc, CurSubmoduleState, PendingModuleMacroNames.size()));
|
||||
BuildingSubmoduleStack.push_back(
|
||||
BuildingSubmoduleInfo(M, ImportLoc, ForPragma, CurSubmoduleState,
|
||||
PendingModuleMacroNames.size()));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -673,8 +694,9 @@ void Preprocessor::EnterSubmodule(Module *M, SourceLocation ImportLoc) {
|
|||
}
|
||||
|
||||
// Track that we entered this module.
|
||||
BuildingSubmoduleStack.push_back(BuildingSubmoduleInfo(
|
||||
M, ImportLoc, CurSubmoduleState, PendingModuleMacroNames.size()));
|
||||
BuildingSubmoduleStack.push_back(
|
||||
BuildingSubmoduleInfo(M, ImportLoc, ForPragma, CurSubmoduleState,
|
||||
PendingModuleMacroNames.size()));
|
||||
|
||||
// Switch to this submodule as the current submodule.
|
||||
CurSubmoduleState = &State;
|
||||
|
@ -697,7 +719,13 @@ bool Preprocessor::needModuleMacros() const {
|
|||
return getLangOpts().isCompilingModule();
|
||||
}
|
||||
|
||||
void Preprocessor::LeaveSubmodule() {
|
||||
Module *Preprocessor::LeaveSubmodule(bool ForPragma) {
|
||||
if (BuildingSubmoduleStack.empty() ||
|
||||
BuildingSubmoduleStack.back().IsPragma != ForPragma) {
|
||||
assert(ForPragma && "non-pragma module enter/leave mismatch");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto &Info = BuildingSubmoduleStack.back();
|
||||
|
||||
Module *LeavingMod = Info.M;
|
||||
|
@ -711,7 +739,7 @@ void Preprocessor::LeaveSubmodule() {
|
|||
// of pending names for the surrounding submodule.
|
||||
BuildingSubmoduleStack.pop_back();
|
||||
makeModuleVisible(LeavingMod, ImportLoc);
|
||||
return;
|
||||
return LeavingMod;
|
||||
}
|
||||
|
||||
// Create ModuleMacros for any macros defined in this submodule.
|
||||
|
@ -800,4 +828,5 @@ void Preprocessor::LeaveSubmodule() {
|
|||
|
||||
// A nested #include makes the included submodule visible.
|
||||
makeModuleVisible(LeavingMod, ImportLoc);
|
||||
return LeavingMod;
|
||||
}
|
||||
|
|
|
@ -1453,7 +1453,7 @@ static bool EvaluateHasIncludeNext(Token &Tok,
|
|||
} else if (PP.isInPrimaryFile()) {
|
||||
Lookup = nullptr;
|
||||
PP.Diag(Tok, diag::pp_include_next_in_primary);
|
||||
} else if (PP.getCurrentSubmodule()) {
|
||||
} else if (PP.getCurrentLexerSubmodule()) {
|
||||
// Start looking up in the directory *after* the one in which the current
|
||||
// file would be found, if any.
|
||||
assert(PP.getCurrentLexer() && "#include_next directive in macro?");
|
||||
|
|
|
@ -534,47 +534,6 @@ void Preprocessor::HandlePragmaDependency(Token &DependencyTok) {
|
|||
}
|
||||
}
|
||||
|
||||
void Preprocessor::HandlePragmaModuleImport(Token &ImportTok) {
|
||||
SourceLocation ImportLoc = ImportTok.getLocation();
|
||||
|
||||
Token Tok;
|
||||
|
||||
llvm::SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 8> ModuleName;
|
||||
while (true) {
|
||||
LexUnexpandedToken(Tok);
|
||||
if (Tok.isNot(tok::identifier)) {
|
||||
Diag(Tok.getLocation(),
|
||||
diag::err_pragma_module_import_expected_module_name) << 0;
|
||||
return;
|
||||
}
|
||||
|
||||
ModuleName.emplace_back(Tok.getIdentifierInfo(), Tok.getLocation());
|
||||
|
||||
LexUnexpandedToken(Tok);
|
||||
assert(Tok.isNot(tok::eof));
|
||||
if (Tok.is(tok::eod))
|
||||
break;
|
||||
if (Tok.isNot(tok::period)) {
|
||||
Diag(Tok.getLocation(),
|
||||
diag::err_pragma_module_import_expected_module_name) << 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If we have a non-empty module path, load the named module.
|
||||
Module *Imported =
|
||||
TheModuleLoader.loadModule(ImportLoc, ModuleName, Module::Hidden,
|
||||
/*IsIncludeDirective=*/false);
|
||||
if (!Imported)
|
||||
return;
|
||||
|
||||
makeModuleVisible(Imported, ImportLoc);
|
||||
EnterAnnotationToken(SourceRange(ImportLoc, Tok.getLocation()),
|
||||
tok::annot_module_include, Imported);
|
||||
if (Callbacks)
|
||||
Callbacks->moduleImport(ImportLoc, ModuleName, Imported);
|
||||
}
|
||||
|
||||
/// ParsePragmaPushOrPopMacro - Handle parsing of pragma push_macro/pop_macro.
|
||||
/// Return the IdentifierInfo* associated with the macro to push or pop.
|
||||
IdentifierInfo *Preprocessor::ParsePragmaPushOrPopMacro(Token &Tok) {
|
||||
|
@ -1342,6 +1301,26 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
static bool LexModuleName(
|
||||
Preprocessor &PP, Token &Tok,
|
||||
llvm::SmallVectorImpl<std::pair<IdentifierInfo *, SourceLocation>>
|
||||
&ModuleName) {
|
||||
while (true) {
|
||||
PP.LexUnexpandedToken(Tok);
|
||||
if (Tok.isNot(tok::identifier)) {
|
||||
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
|
||||
|
@ -1350,8 +1329,108 @@ struct PragmaModuleImportHandler : public PragmaHandler {
|
|||
PragmaModuleImportHandler() : PragmaHandler("import") {}
|
||||
|
||||
void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
|
||||
Token &ImportTok) override {
|
||||
PP.HandlePragmaModuleImport(ImportTok);
|
||||
Token &Tok) override {
|
||||
SourceLocation ImportLoc = Tok.getLocation();
|
||||
|
||||
// Read the module name.
|
||||
llvm::SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 8>
|
||||
ModuleName;
|
||||
if (LexModuleName(PP, Tok, ModuleName))
|
||||
return;
|
||||
|
||||
if (Tok.isNot(tok::eod))
|
||||
PP.Diag(Tok, diag::ext_pp_extra_tokens_at_eol) << "pragma";
|
||||
|
||||
// If we have a non-empty module path, load the named module.
|
||||
Module *Imported =
|
||||
PP.getModuleLoader().loadModule(ImportLoc, ModuleName, Module::Hidden,
|
||||
/*IsIncludeDirective=*/false);
|
||||
if (!Imported)
|
||||
return;
|
||||
|
||||
PP.makeModuleVisible(Imported, ImportLoc);
|
||||
PP.EnterAnnotationToken(SourceRange(ImportLoc, ModuleName.back().second),
|
||||
tok::annot_module_include, Imported);
|
||||
if (auto *CB = PP.getPPCallbacks())
|
||||
CB->moduleImport(ImportLoc, ModuleName, Imported);
|
||||
}
|
||||
};
|
||||
|
||||
/// Handle the clang \#pragma module begin extension. The syntax is:
|
||||
/// \code
|
||||
/// #pragma clang module begin some.module.name
|
||||
/// ...
|
||||
/// #pragma clang module end
|
||||
/// \endcode
|
||||
struct PragmaModuleBeginHandler : public PragmaHandler {
|
||||
PragmaModuleBeginHandler() : PragmaHandler("begin") {}
|
||||
|
||||
void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
|
||||
Token &Tok) override {
|
||||
SourceLocation BeginLoc = Tok.getLocation();
|
||||
|
||||
// Read the module name.
|
||||
llvm::SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 8>
|
||||
ModuleName;
|
||||
if (LexModuleName(PP, Tok, ModuleName))
|
||||
return;
|
||||
|
||||
if (Tok.isNot(tok::eod))
|
||||
PP.Diag(Tok, diag::ext_pp_extra_tokens_at_eol) << "pragma";
|
||||
|
||||
// We can only enter submodules of the current module.
|
||||
StringRef Current = PP.getLangOpts().CurrentModule;
|
||||
if (ModuleName.front().first->getName() != Current) {
|
||||
PP.Diag(ModuleName.front().second, diag::err_pp_module_begin_wrong_module)
|
||||
<< ModuleName.front().first << (ModuleName.size() > 1)
|
||||
<< Current.empty() << Current;
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the module we're entering. We require that a module map for it
|
||||
// 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);
|
||||
if (!M) {
|
||||
PP.Diag(ModuleName.front().second,
|
||||
diag::err_pp_module_begin_no_module_map) << Current;
|
||||
return;
|
||||
}
|
||||
for (unsigned I = 1; I != ModuleName.size(); ++I) {
|
||||
auto *NewM = M->findSubmodule(ModuleName[I].first->getName());
|
||||
if (!NewM) {
|
||||
PP.Diag(ModuleName[I].second, diag::err_pp_module_begin_no_submodule)
|
||||
<< M->getFullModuleName() << ModuleName[I].first;
|
||||
return;
|
||||
}
|
||||
M = NewM;
|
||||
}
|
||||
|
||||
// Enter the scope of the submodule.
|
||||
PP.EnterSubmodule(M, BeginLoc, /*ForPragma*/true);
|
||||
PP.EnterAnnotationToken(SourceRange(BeginLoc, ModuleName.back().second),
|
||||
tok::annot_module_begin, M);
|
||||
}
|
||||
};
|
||||
|
||||
/// Handle the clang \#pragma module end extension.
|
||||
struct PragmaModuleEndHandler : public PragmaHandler {
|
||||
PragmaModuleEndHandler() : PragmaHandler("end") {}
|
||||
|
||||
void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
|
||||
Token &Tok) override {
|
||||
SourceLocation Loc = Tok.getLocation();
|
||||
|
||||
PP.LexUnexpandedToken(Tok);
|
||||
if (Tok.isNot(tok::eod))
|
||||
PP.Diag(Tok, diag::ext_pp_extra_tokens_at_eol) << "pragma";
|
||||
|
||||
Module *M = PP.LeaveSubmodule(/*ForPragma*/true);
|
||||
if (M)
|
||||
PP.EnterAnnotationToken(SourceRange(Loc), tok::annot_module_end, M);
|
||||
else
|
||||
PP.Diag(Loc, diag::err_pp_module_end_without_module_begin);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1582,6 +1661,8 @@ void Preprocessor::RegisterBuiltinPragmas() {
|
|||
auto *ModuleHandler = new PragmaNamespace("module");
|
||||
AddPragmaHandler("clang", ModuleHandler);
|
||||
ModuleHandler->AddPragma(new PragmaModuleImportHandler());
|
||||
ModuleHandler->AddPragma(new PragmaModuleBeginHandler());
|
||||
ModuleHandler->AddPragma(new PragmaModuleEndHandler());
|
||||
|
||||
AddPragmaHandler("STDC", new PragmaSTDC_FENV_ACCESSHandler());
|
||||
AddPragmaHandler("STDC", new PragmaSTDC_CX_LIMITED_RANGEHandler());
|
||||
|
|
|
@ -85,10 +85,10 @@ Preprocessor::Preprocessor(std::shared_ptr<PreprocessorOptions> PPOpts,
|
|||
LastTokenWasAt(false), ModuleImportExpectsIdentifier(false),
|
||||
CodeCompletionReached(false), CodeCompletionII(nullptr),
|
||||
MainFileDir(nullptr), SkipMainFilePreamble(0, true), CurPPLexer(nullptr),
|
||||
CurDirLookup(nullptr), CurLexerKind(CLK_Lexer), CurSubmodule(nullptr),
|
||||
Callbacks(nullptr), CurSubmoduleState(&NullSubmoduleState),
|
||||
MacroArgCache(nullptr), Record(nullptr), MIChainHead(nullptr),
|
||||
DeserialMIChainHead(nullptr) {
|
||||
CurDirLookup(nullptr), CurLexerKind(CLK_Lexer),
|
||||
CurLexerSubmodule(nullptr), Callbacks(nullptr),
|
||||
CurSubmoduleState(&NullSubmoduleState), MacroArgCache(nullptr),
|
||||
Record(nullptr), MIChainHead(nullptr), DeserialMIChainHead(nullptr) {
|
||||
OwnsHeaderSearch = OwnsHeaders;
|
||||
|
||||
CounterValue = 0; // __COUNTER__ starts at 0.
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
#include "file.h"
|
||||
extern int file2;
|
|
@ -1,2 +1,2 @@
|
|||
module fwd { header "fwd.h" export * }
|
||||
module file { header "file.h" export * }
|
||||
module file { header "file.h" header "file2.h" export * }
|
||||
|
|
|
@ -3,10 +3,63 @@
|
|||
// RUN: not %clang_cc1 -fmodules -fmodule-name=file -I%S/Inputs/preprocess -x c++-module-map %S/Inputs/preprocess/module.modulemap -E 2>&1 | FileCheck %s --check-prefix=MISSING-FWD
|
||||
// MISSING-FWD: module 'fwd' is needed
|
||||
|
||||
// RUN: %clang_cc1 -fmodules -fmodule-name=file -fmodules-cache-path=%t -I%S/Inputs/preprocess -x c++-module-map %S/Inputs/preprocess/module.modulemap -E | FileCheck %s
|
||||
// RUN: %clang_cc1 -fmodules -fmodule-name=file -fmodules-cache-path=%t -I%S/Inputs/preprocess -x c++-module-map %S/Inputs/preprocess/module.modulemap -E | FileCheck %s --check-prefix=CHECK --check-prefix=NO-REWRITE
|
||||
// RUN: %clang_cc1 -fmodules -fmodule-name=file -fmodules-cache-path=%t -I%S/Inputs/preprocess -x c++-module-map %S/Inputs/preprocess/module.modulemap -E -frewrite-includes | FileCheck %s --check-prefix=CHECK --check-prefix=REWRITE
|
||||
|
||||
// == file.h
|
||||
// CHECK: # 1 "<module-includes>"
|
||||
// REWRITE: #if 0
|
||||
// REWRITE: #include "file.h"
|
||||
// REWRITE: #endif
|
||||
//
|
||||
// FIXME: It would be preferable to consistently put the module begin/end in
|
||||
// the same file, but the relative ordering of PP callbacks and module
|
||||
// begin/end tokens makes that difficult.
|
||||
//
|
||||
// REWRITE: #pragma clang module begin file
|
||||
// CHECK: # 1 "{{.*}}file.h" 1
|
||||
// NO-REWRITE: #pragma clang module begin file
|
||||
// NO-REWRITE: # 1 "{{.*}}file.h"{{$}}
|
||||
//
|
||||
// CHECK: struct __FILE;
|
||||
// CHECK: #pragma clang module import fwd /* clang -E: implicit import for #include "fwd.h" */
|
||||
// CHECK: #pragma clang module import fwd /* clang {{-E|-frewrite-includes}}: implicit import
|
||||
// CHECK: typedef struct __FILE FILE;
|
||||
//
|
||||
// REWRITE: #pragma clang module end
|
||||
// CHECK: # 2 "<module-includes>" 2
|
||||
// NO-REWRITE: #pragma clang module end
|
||||
|
||||
// == file2.h
|
||||
// REWRITE: #if 0
|
||||
// REWRITE: #include "file2.h"
|
||||
// REWRITE: #endif
|
||||
//
|
||||
// REWRITE: #pragma clang module begin file
|
||||
// CHECK: # 1 "{{.*}}file2.h" 1
|
||||
// NO-REWRITE: #pragma clang module begin file
|
||||
//
|
||||
// ==== recursively re-enter file.h
|
||||
// REWRITE: #if 0
|
||||
// REWRITE: #include "file.h"
|
||||
// REWRITE: #endif
|
||||
//
|
||||
// REWRITE: #pragma clang module begin file
|
||||
// CHECK: # 1 "{{.*}}file.h" 1
|
||||
// NO-REWRITE: #pragma clang module begin file
|
||||
// NO-REWRITE: # 1 "{{.*}}file.h"{{$}}
|
||||
//
|
||||
// CHECK: struct __FILE;
|
||||
// CHECK: #pragma clang module import fwd /* clang {{-E|-frewrite-includes}}: implicit import
|
||||
// CHECK: typedef struct __FILE FILE;
|
||||
//
|
||||
// REWRITE: #pragma clang module end
|
||||
// CHECK: # 2 "{{.*}}file2.h" 2
|
||||
// NO-REWRITE: #pragma clang module end
|
||||
// NO-REWRITE: # 2 "{{.*}}file2.h"{{$}}
|
||||
// ==== return to file2.h
|
||||
//
|
||||
// CHECK: extern int file2;
|
||||
//
|
||||
// REWRITE: #pragma clang module end
|
||||
// CHECK: # 3 "<module-includes>" 2
|
||||
// NO-REWRITE: #pragma clang module end
|
||||
|
|
|
@ -1,11 +1,51 @@
|
|||
// RUN: %clang -cc1 -E -fmodules %s -verify
|
||||
// RUN: rm -rf %t
|
||||
// RUN: mkdir %t
|
||||
// RUN: echo 'module foo { module a {} module b {} } module bar {}' > %t/module.map
|
||||
// RUN: %clang -cc1 -E -fmodules %s -verify -fmodule-name=foo -fmodule-map-file=%t/module.map
|
||||
// RUN: %clang -cc1 -E -fmodules %s -verify -fmodule-name=foo -fmodule-map-file=%t/module.map -fmodules-local-submodule-visibility -DLOCAL_VIS
|
||||
|
||||
// Just checking the syntax here; the semantics are tested elsewhere.
|
||||
#pragma clang module import // expected-error {{expected identifier in module name}}
|
||||
#pragma clang module import ! // expected-error {{expected identifier in module name}}
|
||||
#pragma clang module import if // expected-error {{expected identifier in module name}}
|
||||
#pragma clang module import foo ? bar // expected-error {{expected '.' or end of directive after module name}}
|
||||
#pragma clang module import foo. // expected-error {{expected identifier}}
|
||||
#pragma clang module import foo.bar.baz.quux // expected-error {{module 'foo' not found}}
|
||||
#pragma clang module import // expected-error {{expected module name}}
|
||||
#pragma clang module import ! // expected-error {{expected module name}}
|
||||
#pragma clang module import if // expected-error {{expected module name}}
|
||||
#pragma clang module import foo ? bar // expected-warning {{extra tokens at end of #pragma}}
|
||||
#pragma clang module import foo. // expected-error {{expected identifier after '.' in module name}}
|
||||
#pragma clang module import foo.bar.baz.quux // expected-error {{no submodule named 'bar' in module 'foo'}}
|
||||
|
||||
#error here // expected-error {{here}}
|
||||
#pragma clang module begin ! // expected-error {{expected module name}}
|
||||
|
||||
#pragma clang module begin foo.a blah // expected-warning {{extra tokens}}
|
||||
#pragma clang module begin foo.a // nesting is OK
|
||||
#define X 1 // expected-note 0-1{{previous}}
|
||||
#ifndef X
|
||||
#error X should be defined here
|
||||
#endif
|
||||
#pragma clang module end
|
||||
|
||||
#ifndef X
|
||||
#error X should still be defined
|
||||
#endif
|
||||
#pragma clang module end foo.a // expected-warning {{extra tokens}}
|
||||
|
||||
// #pragma clang module begin/end also import the module into the enclosing context
|
||||
#ifndef X
|
||||
#error X should still be defined
|
||||
#endif
|
||||
|
||||
#pragma clang module begin foo.b
|
||||
#if defined(X) && defined(LOCAL_VIS)
|
||||
#error under -fmodules-local-submodule-visibility, X should not be defined
|
||||
#endif
|
||||
|
||||
#if !defined(X) && !defined(LOCAL_VIS)
|
||||
#error without -fmodules-local-submodule-visibility, X should still be defined
|
||||
#endif
|
||||
|
||||
#pragma clang module import foo.a
|
||||
#ifndef X
|
||||
#error X should be defined here
|
||||
#endif
|
||||
#pragma clang module end
|
||||
|
||||
#pragma clang module end // expected-error {{no matching '#pragma clang module begin'}}
|
||||
#pragma clang module begin foo.a // expected-error {{no matching '#pragma clang module end'}}
|
||||
|
|
Loading…
Reference in New Issue