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:
Richard Smith 2017-05-04 00:29:54 +00:00
parent 8e23870585
commit d13863008b
13 changed files with 379 additions and 96 deletions

View File

@ -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<

View File

@ -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);

View File

@ -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() &&

View File

@ -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);

View File

@ -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?");

View File

@ -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;
}

View File

@ -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?");

View File

@ -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());

View File

@ -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.

View File

@ -0,0 +1,2 @@
#include "file.h"
extern int file2;

View File

@ -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 * }

View File

@ -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

View File

@ -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'}}