r358231 - [C++20] Implement context-sensitive header-name lexing and pp-import parsing in the preprocessor.
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Thu Apr 11 14:18:24 PDT 2019
Author: rsmith
Date: Thu Apr 11 14:18:23 2019
New Revision: 358231
URL: http://llvm.org/viewvc/llvm-project?rev=358231&view=rev
Log:
[C++20] Implement context-sensitive header-name lexing and pp-import parsing in the preprocessor.
Added:
cfe/trunk/test/CXX/cpp/cpp.module/
cfe/trunk/test/CXX/cpp/cpp.module/Inputs/
cfe/trunk/test/CXX/cpp/cpp.module/Inputs/attrs.h
cfe/trunk/test/CXX/cpp/cpp.module/Inputs/empty.h
cfe/trunk/test/CXX/cpp/cpp.module/p1.cpp
cfe/trunk/test/CXX/cpp/cpp.module/p2.cpp
cfe/trunk/test/CXX/lex/lex.pptoken/Inputs/
cfe/trunk/test/CXX/lex/lex.pptoken/Inputs/foo bar
cfe/trunk/test/CXX/lex/lex.pptoken/Inputs/foo bar
cfe/trunk/test/CXX/lex/lex.pptoken/p3-2a.cpp
Modified:
cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td
cfe/trunk/include/clang/Basic/LangOptions.def
cfe/trunk/include/clang/Basic/LangOptions.h
cfe/trunk/include/clang/Basic/TokenKinds.def
cfe/trunk/include/clang/Lex/Preprocessor.h
cfe/trunk/lib/Basic/IdentifierTable.cpp
cfe/trunk/lib/Frontend/CompilerInvocation.cpp
cfe/trunk/lib/Frontend/PrintPreprocessedOutput.cpp
cfe/trunk/lib/Lex/PPCaching.cpp
cfe/trunk/lib/Lex/PPDirectives.cpp
cfe/trunk/lib/Lex/Preprocessor.cpp
cfe/trunk/lib/Lex/TokenConcatenation.cpp
cfe/trunk/test/Modules/framework-name.m
cfe/trunk/test/Modules/module_file_info.m
Modified: cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td?rev=358231&r1=358230&r2=358231&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td Thu Apr 11 14:18:23 2019
@@ -418,7 +418,8 @@ def warn_pp_hdrstop_filename_ignored : W
"/Fp can be used to specify precompiled header filename">,
InGroup<ClangClPch>;
def err_pp_file_not_found_angled_include_not_fatal : Error<
- "'%0' file not found with <angled> include; use \"quotes\" instead">;
+ "'%0' file not found with <angled> %select{include|import}1; "
+ "use \"quotes\" instead">;
def err_pp_file_not_found_typo_not_fatal
: Error<"'%0' file not found, did you mean '%1'?">;
def note_pp_framework_without_header : Note<
@@ -642,7 +643,8 @@ def err_pp_double_begin_of_arc_cf_code_a
def err_pp_unmatched_end_of_arc_cf_code_audited : Error<
"not currently inside '#pragma clang arc_cf_code_audited'">;
def err_pp_include_in_arc_cf_code_audited : Error<
- "cannot #include files inside '#pragma clang arc_cf_code_audited'">;
+ "cannot %select{#include files|import headers}0 "
+ "inside '#pragma clang arc_cf_code_audited'">;
def err_pp_eof_in_arc_cf_code_audited : Error<
"'#pragma clang arc_cf_code_audited' was not ended within this file">;
@@ -776,6 +778,14 @@ def warn_module_conflict : Warning<
"module '%0' conflicts with already-imported module '%1': %2">,
InGroup<ModuleConflict>;
+// C++20 modules
+def err_header_import_semi_in_macro : Error<
+ "semicolon terminating header import declaration cannot be produced "
+ "by a macro">;
+def err_header_import_not_header_unit : Error<
+ "header file %0 (aka '%1') cannot be imported because "
+ "it is not known to be a header unit">;
+
def warn_header_guard : Warning<
"%0 is used as a header guard here, followed by #define of a different macro">,
InGroup<DiagGroup<"header-guard">>;
@@ -797,7 +807,8 @@ def err_pp_double_begin_of_assume_nonnul
def err_pp_unmatched_end_of_assume_nonnull : Error<
"not currently inside '#pragma clang assume_nonnull'">;
def err_pp_include_in_assume_nonnull : Error<
- "cannot #include files inside '#pragma clang assume_nonnull'">;
+ "cannot %select{#include files|import headers}0 "
+ "inside '#pragma clang assume_nonnull'">;
def err_pp_eof_in_assume_nonnull : Error<
"'#pragma clang assume_nonnull' was not ended within this file">;
Modified: cfe/trunk/include/clang/Basic/LangOptions.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/LangOptions.def?rev=358231&r1=358230&r2=358231&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/LangOptions.def (original)
+++ cfe/trunk/include/clang/Basic/LangOptions.def Thu Apr 11 14:18:23 2019
@@ -148,8 +148,9 @@ LANGOPT(Blocks , 1, 0, "block
BENIGN_LANGOPT(EmitAllDecls , 1, 0, "emitting all declarations")
LANGOPT(MathErrno , 1, 1, "errno in math functions")
BENIGN_LANGOPT(HeinousExtensions , 1, 0, "extensions that we really don't like and may be ripped out at any time")
-LANGOPT(Modules , 1, 0, "modules extension to C")
-COMPATIBLE_LANGOPT(ModulesTS , 1, 0, "C++ Modules TS")
+LANGOPT(Modules , 1, 0, "modules semantics")
+COMPATIBLE_LANGOPT(ModulesTS , 1, 0, "C++ Modules TS syntax")
+COMPATIBLE_LANGOPT(CPlusPlusModules, 1, 0, "C++ modules syntax")
BENIGN_ENUM_LANGOPT(CompilingModule, CompilingModuleKind, 2, CMK_None,
"compiling a module interface")
BENIGN_LANGOPT(CompilingPCH, 1, 0, "building a pch")
Modified: cfe/trunk/include/clang/Basic/LangOptions.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/LangOptions.h?rev=358231&r1=358230&r2=358231&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/LangOptions.h (original)
+++ cfe/trunk/include/clang/Basic/LangOptions.h Thu Apr 11 14:18:23 2019
@@ -265,7 +265,7 @@ public:
/// Do we need to track the owning module for a local declaration?
bool trackLocalOwningModule() const {
- return isCompilingModule() || ModulesLocalVisibility || ModulesTS;
+ return isCompilingModule() || ModulesLocalVisibility;
}
bool isSignedOverflowDefined() const {
Modified: cfe/trunk/include/clang/Basic/TokenKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/TokenKinds.def?rev=358231&r1=358230&r2=358231&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/TokenKinds.def (original)
+++ cfe/trunk/include/clang/Basic/TokenKinds.def Thu Apr 11 14:18:23 2019
@@ -827,6 +827,10 @@ ANNOTATION(module_include)
ANNOTATION(module_begin)
ANNOTATION(module_end)
+// Annotation for a header_name token that has been looked up and transformed
+// into the name of a header unit.
+ANNOTATION(header_unit)
+
#undef ANNOTATION
#undef TESTING_KEYWORD
#undef OBJC_AT_KEYWORD
Modified: cfe/trunk/include/clang/Lex/Preprocessor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/Preprocessor.h?rev=358231&r1=358230&r2=358231&view=diff
==============================================================================
--- cfe/trunk/include/clang/Lex/Preprocessor.h (original)
+++ cfe/trunk/include/clang/Lex/Preprocessor.h Thu Apr 11 14:18:23 2019
@@ -285,6 +285,84 @@ class Preprocessor {
/// Whether the last token we lexed was an '@'.
bool LastTokenWasAt = false;
+ /// A position within a C++20 import-seq.
+ class ImportSeq {
+ public:
+ enum State : int {
+ // Positive values represent a number of unclosed brackets.
+ AtTopLevel = 0,
+ AfterTopLevelTokenSeq = -1,
+ AfterExport = -2,
+ AfterImportSeq = -3,
+ };
+
+ ImportSeq(State S) : S(S) {}
+
+ /// Saw any kind of open bracket.
+ void handleOpenBracket() {
+ S = static_cast<State>(std::max<int>(S, 0) + 1);
+ }
+ /// Saw any kind of close bracket other than '}'.
+ void handleCloseBracket() {
+ S = static_cast<State>(std::max<int>(S, 1) - 1);
+ }
+ /// Saw a close brace.
+ void handleCloseBrace() {
+ handleCloseBracket();
+ if (S == AtTopLevel && !AfterHeaderName)
+ S = AfterTopLevelTokenSeq;
+ }
+ /// Saw a semicolon.
+ void handleSemi() {
+ if (atTopLevel()) {
+ S = AfterTopLevelTokenSeq;
+ AfterHeaderName = false;
+ }
+ }
+
+ /// Saw an 'export' identifier.
+ void handleExport() {
+ if (S == AfterTopLevelTokenSeq)
+ S = AfterExport;
+ else if (S <= 0)
+ S = AtTopLevel;
+ }
+ /// Saw an 'import' identifier.
+ void handleImport() {
+ if (S == AfterTopLevelTokenSeq || S == AfterExport)
+ S = AfterImportSeq;
+ else if (S <= 0)
+ S = AtTopLevel;
+ }
+
+ /// Saw a 'header-name' token; do not recognize any more 'import' tokens
+ /// until we reach a top-level semicolon.
+ void handleHeaderName() {
+ if (S == AfterImportSeq)
+ AfterHeaderName = true;
+ handleMisc();
+ }
+
+ /// Saw any other token.
+ void handleMisc() {
+ if (S <= 0)
+ S = AtTopLevel;
+ }
+
+ bool atTopLevel() { return S <= 0; }
+ bool afterImportSeq() { return S == AfterImportSeq; }
+
+ private:
+ State S;
+ /// Whether we're in the pp-import-suffix following the header-name in a
+ /// pp-import. If so, a close-brace is not sufficient to end the
+ /// top-level-token-seq of an import-seq.
+ bool AfterHeaderName = false;
+ };
+
+ /// Our current position within a C++20 import-seq.
+ ImportSeq ImportSeqState = ImportSeq::AfterTopLevelTokenSeq;
+
/// Whether the module import expects an identifier next. Otherwise,
/// it expects a '.' or ';'.
bool ModuleImportExpectsIdentifier = false;
@@ -1266,7 +1344,8 @@ public:
/// Lex a token, forming a header-name token if possible.
bool LexHeaderName(Token &Result, bool AllowMacroExpansion = true);
- void LexAfterModuleImport(Token &Result);
+ bool LexAfterModuleImport(Token &Result);
+ void CollectPpImportSuffix(SmallVectorImpl<Token> &Toks);
void makeModuleVisible(Module *M, SourceLocation Loc);
@@ -1813,7 +1892,11 @@ public:
/// If not, emit a diagnostic and consume up until the eod.
/// If \p EnableMacros is true, then we consider macros that expand to zero
/// tokens as being ok.
- void CheckEndOfDirective(const char *DirType, bool EnableMacros = false);
+ ///
+ /// \return The location of the end of the directive (the terminating
+ /// newline).
+ SourceLocation CheckEndOfDirective(const char *DirType,
+ bool EnableMacros = false);
/// Read and discard all tokens remaining on the current line until
/// the tok::eod token is found. Returns the range of the skipped tokens.
@@ -2052,7 +2135,7 @@ private:
//===--------------------------------------------------------------------===//
// Caching stuff.
- void CachingLex(Token &Result);
+ void CachingLex(Token &Result, bool &IsNewToken);
bool InCachingLexMode() const {
// If the Lexer pointers are 0 and IncludeMacroStack is empty, it means
@@ -2082,12 +2165,31 @@ private:
void HandleMacroPublicDirective(Token &Tok);
void HandleMacroPrivateDirective();
+ /// An additional notification that can be produced by a header inclusion or
+ /// import to tell the parser what happened.
+ struct ImportAction {
+ enum ActionKind {
+ None,
+ ModuleBegin,
+ ModuleImport,
+ } Kind;
+ Module *ModuleForHeader = nullptr;
+
+ ImportAction(ActionKind AK, Module *Mod = nullptr)
+ : Kind(AK), ModuleForHeader(Mod) {
+ assert((AK == None || Mod) && "no module for module action");
+ }
+ };
+
// File inclusion.
- void HandleIncludeDirective(SourceLocation HashLoc,
- Token &Tok,
+ void HandleIncludeDirective(SourceLocation HashLoc, Token &Tok,
+ const DirectoryLookup *LookupFrom = nullptr,
+ const FileEntry *LookupFromFile = nullptr);
+ ImportAction
+ HandleHeaderIncludeOrImport(SourceLocation HashLoc, Token &IncludeTok,
+ Token &FilenameTok, SourceLocation EndLoc,
const DirectoryLookup *LookupFrom = nullptr,
- const FileEntry *LookupFromFile = nullptr,
- bool isImport = false);
+ const FileEntry *LookupFromFile = nullptr);
void HandleIncludeNextDirective(SourceLocation HashLoc, Token &Tok);
void HandleIncludeMacrosDirective(SourceLocation HashLoc, Token &Tok);
void HandleImportDirective(SourceLocation HashLoc, Token &Tok);
Modified: cfe/trunk/lib/Basic/IdentifierTable.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/IdentifierTable.cpp?rev=358231&r1=358230&r2=358231&view=diff
==============================================================================
--- cfe/trunk/lib/Basic/IdentifierTable.cpp (original)
+++ cfe/trunk/lib/Basic/IdentifierTable.cpp Thu Apr 11 14:18:23 2019
@@ -218,7 +218,7 @@ void IdentifierTable::AddKeywords(const
if (LangOpts.DeclSpecKeyword)
AddKeyword("__declspec", tok::kw___declspec, KEYALL, LangOpts, *this);
- // Add the '_experimental_modules_import' contextual keyword.
+ // Add the 'import' contextual keyword.
get("import").setModulesImport(true);
}
Modified: cfe/trunk/lib/Frontend/CompilerInvocation.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CompilerInvocation.cpp?rev=358231&r1=358230&r2=358231&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/CompilerInvocation.cpp (original)
+++ cfe/trunk/lib/Frontend/CompilerInvocation.cpp Thu Apr 11 14:18:23 2019
@@ -2594,13 +2594,18 @@ static void ParseLangArgs(LangOptions &O
Args.hasFlag(OPT_fdouble_square_bracket_attributes,
OPT_fno_double_square_bracket_attributes, Opts.CPlusPlus11);
+ Opts.CPlusPlusModules = Opts.CPlusPlus2a;
Opts.ModulesTS = Args.hasArg(OPT_fmodules_ts);
- Opts.Modules = Args.hasArg(OPT_fmodules) || Opts.ModulesTS;
+ Opts.Modules =
+ Args.hasArg(OPT_fmodules) || Opts.ModulesTS || Opts.CPlusPlusModules;
Opts.ModulesStrictDeclUse = Args.hasArg(OPT_fmodules_strict_decluse);
Opts.ModulesDeclUse =
Args.hasArg(OPT_fmodules_decluse) || Opts.ModulesStrictDeclUse;
+ // FIXME: We only need this in C++ modules / Modules TS if we might textually
+ // enter a different module (eg, when building a header unit).
Opts.ModulesLocalVisibility =
- Args.hasArg(OPT_fmodules_local_submodule_visibility) || Opts.ModulesTS;
+ Args.hasArg(OPT_fmodules_local_submodule_visibility) || Opts.ModulesTS ||
+ Opts.CPlusPlusModules;
Opts.ModulesCodegen = Args.hasArg(OPT_fmodules_codegen);
Opts.ModulesDebugInfo = Args.hasArg(OPT_fmodules_debuginfo);
Opts.ModulesSearchAll = Opts.Modules &&
Modified: cfe/trunk/lib/Frontend/PrintPreprocessedOutput.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/PrintPreprocessedOutput.cpp?rev=358231&r1=358230&r2=358231&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/PrintPreprocessedOutput.cpp (original)
+++ cfe/trunk/lib/Frontend/PrintPreprocessedOutput.cpp Thu Apr 11 14:18:23 2019
@@ -769,6 +769,15 @@ static void PrintPreprocessedTokens(Prep
reinterpret_cast<Module *>(Tok.getAnnotationValue()));
PP.Lex(Tok);
continue;
+ } else if (Tok.is(tok::annot_header_unit)) {
+ // This is a header-name that has been (effectively) converted into a
+ // module-name.
+ // FIXME: The module name could contain non-identifier module name
+ // components. We don't have a good way to round-trip those.
+ Module *M = reinterpret_cast<Module *>(Tok.getAnnotationValue());
+ std::string Name = M->getFullModuleName();
+ OS.write(Name.data(), Name.size());
+ Callbacks->HandleNewlinesInToken(Name.data(), Name.size());
} else if (Tok.isAnnotation()) {
// Ignore annotation tokens created by pragmas - the pragmas themselves
// will be reproduced in the preprocessed output.
@@ -790,12 +799,12 @@ static void PrintPreprocessedTokens(Prep
Callbacks->HandleNewlinesInToken(TokPtr, Len);
} else {
std::string S = PP.getSpelling(Tok);
- OS.write(&S[0], S.size());
+ OS.write(S.data(), S.size());
// Tokens that can contain embedded newlines need to adjust our current
// line number.
if (Tok.getKind() == tok::comment || Tok.getKind() == tok::unknown)
- Callbacks->HandleNewlinesInToken(&S[0], S.size());
+ Callbacks->HandleNewlinesInToken(S.data(), S.size());
}
Callbacks->setEmittedTokensOnThisLine();
Modified: cfe/trunk/lib/Lex/PPCaching.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPCaching.cpp?rev=358231&r1=358230&r2=358231&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/PPCaching.cpp (original)
+++ cfe/trunk/lib/Lex/PPCaching.cpp Thu Apr 11 14:18:23 2019
@@ -45,7 +45,7 @@ void Preprocessor::Backtrack() {
recomputeCurLexerKind();
}
-void Preprocessor::CachingLex(Token &Result) {
+void Preprocessor::CachingLex(Token &Result, bool &IsNewToken) {
if (!InCachingLexMode())
return;
@@ -55,6 +55,7 @@ void Preprocessor::CachingLex(Token &Res
if (CachedLexPos < CachedTokens.size()) {
Result = CachedTokens[CachedLexPos++];
+ IsNewToken = false;
return;
}
Modified: cfe/trunk/lib/Lex/PPDirectives.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPDirectives.cpp?rev=358231&r1=358230&r2=358231&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/PPDirectives.cpp (original)
+++ cfe/trunk/lib/Lex/PPDirectives.cpp Thu Apr 11 14:18:23 2019
@@ -336,7 +336,10 @@ void Preprocessor::ReadMacroName(Token &
///
/// If not, emit a diagnostic and consume up until the eod. If EnableMacros is
/// true, then we consider macros that expand to zero tokens as being ok.
-void Preprocessor::CheckEndOfDirective(const char *DirType, bool EnableMacros) {
+///
+/// Returns the location of the end of the directive.
+SourceLocation Preprocessor::CheckEndOfDirective(const char *DirType,
+ bool EnableMacros) {
Token Tmp;
// Lex unexpanded tokens for most directives: macros might expand to zero
// tokens, causing us to miss diagnosing invalid lines. Some directives (like
@@ -351,18 +354,19 @@ void Preprocessor::CheckEndOfDirective(c
while (Tmp.is(tok::comment)) // Skip comments in -C mode.
LexUnexpandedToken(Tmp);
- if (Tmp.isNot(tok::eod)) {
- // Add a fixit in GNU/C99/C++ mode. Don't offer a fixit for strict-C89,
- // or if this is a macro-style preprocessing directive, because it is more
- // trouble than it is worth to insert /**/ and check that there is no /**/
- // in the range also.
- FixItHint Hint;
- if ((LangOpts.GNUMode || LangOpts.C99 || LangOpts.CPlusPlus) &&
- !CurTokenLexer)
- Hint = FixItHint::CreateInsertion(Tmp.getLocation(),"//");
- Diag(Tmp, diag::ext_pp_extra_tokens_at_eol) << DirType << Hint;
- DiscardUntilEndOfDirective();
- }
+ if (Tmp.is(tok::eod))
+ return Tmp.getLocation();
+
+ // Add a fixit in GNU/C99/C++ mode. Don't offer a fixit for strict-C89,
+ // or if this is a macro-style preprocessing directive, because it is more
+ // trouble than it is worth to insert /**/ and check that there is no /**/
+ // in the range also.
+ FixItHint Hint;
+ if ((LangOpts.GNUMode || LangOpts.C99 || LangOpts.CPlusPlus) &&
+ !CurTokenLexer)
+ Hint = FixItHint::CreateInsertion(Tmp.getLocation(),"//");
+ Diag(Tmp, diag::ext_pp_extra_tokens_at_eol) << DirType << Hint;
+ return DiscardUntilEndOfDirective().getEnd();
}
/// SkipExcludedConditionalBlock - We just read a \#if or related directive and
@@ -1509,7 +1513,13 @@ static void diagnoseAutoModuleImport(
Preprocessor &PP, SourceLocation HashLoc, Token &IncludeTok,
ArrayRef<std::pair<IdentifierInfo *, SourceLocation>> Path,
SourceLocation PathEnd) {
- assert(PP.getLangOpts().ObjC && "no import syntax available");
+ StringRef ImportKeyword;
+ if (PP.getLangOpts().ObjC)
+ ImportKeyword = "@import";
+ else if (PP.getLangOpts().ModulesTS || PP.getLangOpts().CPlusPlusModules)
+ ImportKeyword = "import";
+ else
+ return; // no import syntax available
SmallString<128> PathString;
for (size_t I = 0, N = Path.size(); I != N; ++I) {
@@ -1544,8 +1554,8 @@ static void diagnoseAutoModuleImport(
/*IsTokenRange=*/false);
PP.Diag(HashLoc, diag::warn_auto_module_import)
<< IncludeKind << PathString
- << FixItHint::CreateReplacement(ReplaceRange,
- ("@import " + PathString + ";").str());
+ << FixItHint::CreateReplacement(
+ ReplaceRange, (ImportKeyword + " " + PathString + ";").str());
}
// Given a vector of path components and a string containing the real
@@ -1615,8 +1625,7 @@ bool Preprocessor::checkModuleIsAvailabl
void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
Token &IncludeTok,
const DirectoryLookup *LookupFrom,
- const FileEntry *LookupFromFile,
- bool isImport) {
+ const FileEntry *LookupFromFile) {
Token FilenameTok;
if (LexHeaderName(FilenameTok))
return;
@@ -1628,32 +1637,66 @@ void Preprocessor::HandleIncludeDirectiv
return;
}
+ // Verify that there is nothing after the filename, other than EOD. Note
+ // that we allow macros that expand to nothing after the filename, because
+ // this falls into the category of "#include pp-tokens new-line" specified
+ // in C99 6.10.2p4.
+ SourceLocation EndLoc =
+ CheckEndOfDirective(IncludeTok.getIdentifierInfo()->getNameStart(), true);
+
+ auto Action = HandleHeaderIncludeOrImport(HashLoc, IncludeTok, FilenameTok,
+ EndLoc, LookupFrom, LookupFromFile);
+ switch (Action.Kind) {
+ case ImportAction::None:
+ break;
+ case ImportAction::ModuleBegin:
+ EnterAnnotationToken(SourceRange(HashLoc, EndLoc),
+ tok::annot_module_begin, Action.ModuleForHeader);
+ break;
+ case ImportAction::ModuleImport:
+ EnterAnnotationToken(SourceRange(HashLoc, EndLoc),
+ tok::annot_module_include, Action.ModuleForHeader);
+ break;
+ }
+}
+
+/// Handle either a #include-like directive or an import declaration that names
+/// a header file.
+///
+/// \param HashLoc The location of the '#' token for an include, or
+/// SourceLocation() for an import declaration.
+/// \param IncludeTok The include / include_next / import token.
+/// \param FilenameTok The header-name token.
+/// \param EndLoc The location at which any imported macros become visible.
+/// \param LookupFrom For #include_next, the starting directory for the
+/// directory lookup.
+/// \param LookupFromFile For #include_next, the starting file for the directory
+/// lookup.
+Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
+ SourceLocation HashLoc, Token &IncludeTok, Token &FilenameTok,
+ SourceLocation EndLoc, const DirectoryLookup *LookupFrom,
+ const FileEntry *LookupFromFile) {
SmallString<128> FilenameBuffer;
StringRef Filename = getSpelling(FilenameTok, FilenameBuffer);
SourceLocation CharEnd = FilenameTok.getEndLoc();
CharSourceRange FilenameRange
= CharSourceRange::getCharRange(FilenameTok.getLocation(), CharEnd);
- SourceRange DirectiveRange(HashLoc, FilenameTok.getLocation());
StringRef OriginalFilename = Filename;
bool isAngled =
GetIncludeFilenameSpelling(FilenameTok.getLocation(), Filename);
+
// If GetIncludeFilenameSpelling set the start ptr to null, there was an
// error.
- if (Filename.empty()) {
- DiscardUntilEndOfDirective();
- return;
- }
+ if (Filename.empty())
+ return {ImportAction::None};
- // Verify that there is nothing after the filename, other than EOD. Note that
- // we allow macros that expand to nothing after the filename, because this
- // falls into the category of "#include pp-tokens new-line" specified in
- // C99 6.10.2p4.
- CheckEndOfDirective(IncludeTok.getIdentifierInfo()->getNameStart(), true);
+ bool IsImportDecl = HashLoc.isInvalid();
+ SourceLocation StartLoc = IsImportDecl ? IncludeTok.getLocation() : HashLoc;
// Complain about attempts to #include files in an audit pragma.
if (PragmaARCCFCodeAuditedLoc.isValid()) {
- Diag(HashLoc, diag::err_pp_include_in_arc_cf_code_audited);
+ Diag(StartLoc, diag::err_pp_include_in_arc_cf_code_audited) << IsImportDecl;
Diag(PragmaARCCFCodeAuditedLoc, diag::note_pragma_entered_here);
// Immediately leave the pragma.
@@ -1662,7 +1705,7 @@ void Preprocessor::HandleIncludeDirectiv
// Complain about attempts to #include files in an assume-nonnull pragma.
if (PragmaAssumeNonNullLoc.isValid()) {
- Diag(HashLoc, diag::err_pp_include_in_assume_nonnull);
+ Diag(StartLoc, diag::err_pp_include_in_assume_nonnull) << IsImportDecl;
Diag(PragmaAssumeNonNullLoc, diag::note_pragma_entered_here);
// Immediately leave the pragma.
@@ -1737,7 +1780,7 @@ void Preprocessor::HandleIncludeDirectiv
if (File) {
Diag(FilenameTok,
diag::err_pp_file_not_found_angled_include_not_fatal)
- << Filename
+ << Filename << IsImportDecl
<< FixItHint::CreateReplacement(FilenameRange,
"\"" + Filename.str() + "\"");
}
@@ -1810,7 +1853,7 @@ void Preprocessor::HandleIncludeDirectiv
if (usingPCHWithThroughHeader() && SkippingUntilPCHThroughHeader) {
if (isPCHThroughHeader(File))
SkippingUntilPCHThroughHeader = false;
- return;
+ return {ImportAction::None};
}
// Should we enter the source file? Set to Skip if either the source file is
@@ -1845,7 +1888,7 @@ void Preprocessor::HandleIncludeDirectiv
Diag(FilenameTok.getLocation(),
diag::note_implicit_top_level_module_import_here)
<< SuggestedModule.getModule()->getTopLevelModuleName();
- return;
+ return {ImportAction::None};
}
// Compute the module access path corresponding to this module.
@@ -1858,9 +1901,8 @@ void Preprocessor::HandleIncludeDirectiv
std::reverse(Path.begin(), Path.end());
// Warn that we're replacing the include/import with a module import.
- // We only do this in Objective-C, where we have a module-import syntax.
- if (getLangOpts().ObjC)
- diagnoseAutoModuleImport(*this, HashLoc, IncludeTok, Path, CharEnd);
+ if (!IsImportDecl)
+ diagnoseAutoModuleImport(*this, StartLoc, IncludeTok, Path, CharEnd);
// Load the module to import its macros. We'll make the declarations
// visible when the parser gets here.
@@ -1893,7 +1935,7 @@ void Preprocessor::HandleIncludeDirectiv
CurLexer->FormTokenWithChars(Result, CurLexer->BufferEnd, tok::eof);
CurLexer->cutOffLexing();
}
- return;
+ return {ImportAction::None};
}
}
@@ -1905,10 +1947,19 @@ void Preprocessor::HandleIncludeDirectiv
if (File)
FileCharacter = std::max(HeaderInfo.getFileDirFlavor(File), FileCharacter);
+ // If this is a '#import' or an import-declaration, don't re-enter the file.
+ //
+ // FIXME: If we have a suggested module for a '#include', and we've already
+ // visited this file, don't bother entering it again. We know it has no
+ // further effect.
+ bool EnterOnce =
+ IsImportDecl ||
+ IncludeTok.getIdentifierInfo()->getPPKeywordID() == tok::pp_import;
+
// Ask HeaderInfo if we should enter this #include file. If not, #including
// this file will have no effect.
if (Action == Enter && File &&
- !HeaderInfo.ShouldEnterIncludeFile(*this, File, isImport,
+ !HeaderInfo.ShouldEnterIncludeFile(*this, File, EnterOnce,
getLangOpts().Modules,
SuggestedModule.getModule())) {
// Even if we've already preprocessed this header once and know that we
@@ -1921,8 +1972,9 @@ void Preprocessor::HandleIncludeDirectiv
Action = (SuggestedModule && !getLangOpts().CompilingPCH) ? Import : Skip;
}
- if (Callbacks) {
+ if (Callbacks && !IsImportDecl) {
// Notify the callback object that we've seen an inclusion directive.
+ // FIXME: Use a different callback for a pp-import?
Callbacks->InclusionDirective(
HashLoc, IncludeTok,
LangOpts.MSVCCompat ? NormalizedPath.c_str() : Filename, isAngled,
@@ -1934,10 +1986,15 @@ void Preprocessor::HandleIncludeDirectiv
}
if (!File)
- return;
+ return {ImportAction::None};
- // FIXME: If we have a suggested module, and we've already visited this file,
- // don't bother entering it again. We know it has no further effect.
+ // If this is a C++20 pp-import declaration, diagnose if we didn't find any
+ // module corresponding to the named header.
+ if (IsImportDecl && !SuggestedModule) {
+ Diag(FilenameTok, diag::err_header_import_not_header_unit)
+ << OriginalFilename << File->getName();
+ return {ImportAction::None};
+ }
// Issue a diagnostic if the name of the file on disk has a different case
// than the one we're about to open.
@@ -1977,24 +2034,25 @@ void Preprocessor::HandleIncludeDirectiv
switch (Action) {
case Skip:
// If we don't need to enter the file, stop now.
- return;
+ return {ImportAction::None};
case IncludeLimitReached:
// If we reached our include limit and don't want to enter any more files,
// don't go any further.
- return;
+ return {ImportAction::None};
case Import: {
// If this is a module import, make it visible if needed.
Module *M = SuggestedModule.getModule();
assert(M && "no module to import");
- makeModuleVisible(M, HashLoc);
+ makeModuleVisible(M, EndLoc);
- if (IncludeTok.getIdentifierInfo()->getPPKeywordID() !=
+ if (IncludeTok.getIdentifierInfo()->getPPKeywordID() ==
tok::pp___include_macros)
- EnterAnnotationToken(DirectiveRange, tok::annot_module_include, M);
- return;
+ return {ImportAction::None};
+
+ return {ImportAction::ModuleImport, M};
}
case Enter:
@@ -2005,7 +2063,7 @@ void Preprocessor::HandleIncludeDirectiv
if (IncludeMacroStack.size() == MaxAllowedIncludeStackDepth-1) {
Diag(FilenameTok, diag::err_pp_include_too_deep);
HasReachedMaxIncludeDepth = true;
- return;
+ return {ImportAction::None};
}
// Look up the file, create a File ID for it.
@@ -2019,7 +2077,7 @@ void Preprocessor::HandleIncludeDirectiv
// If all is good, enter the new file!
if (EnterSourceFile(FID, CurDir, FilenameTok.getLocation()))
- return;
+ return {ImportAction::None};
// Determine if we're switching to building a new submodule, and which one.
if (auto *M = SuggestedModule.getModule()) {
@@ -2030,7 +2088,7 @@ void Preprocessor::HandleIncludeDirectiv
<< M->getFullModuleName();
Diag(M->getTopLevelModule()->ShadowingModule->DefinitionLoc,
diag::note_previous_definition);
- return;
+ return {ImportAction::None};
}
// When building a pch, -fmodule-name tells the compiler to textually
// include headers in the specified module. We are not building the
@@ -2043,21 +2101,23 @@ void Preprocessor::HandleIncludeDirectiv
if (getLangOpts().CompilingPCH &&
isForModuleBuilding(M, getLangOpts().CurrentModule,
getLangOpts().ModuleName))
- return;
+ return {ImportAction::None};
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, /*ForPragma*/false);
+ EnterSubmodule(M, EndLoc, /*ForPragma*/false);
// Let the parser know that any future declarations are within the new
// submodule.
// FIXME: There's no point doing this if we're handling a #__include_macros
// directive.
- EnterAnnotationToken(DirectiveRange, tok::annot_module_begin, M);
+ return {ImportAction::ModuleBegin, M};
}
+
+ return {ImportAction::None};
}
/// HandleIncludeNextDirective - Implements \#include_next.
@@ -2122,7 +2182,7 @@ void Preprocessor::HandleImportDirective
return HandleMicrosoftImportDirective(ImportTok);
Diag(ImportTok, diag::ext_pp_import_directive);
}
- return HandleIncludeDirective(HashLoc, ImportTok, nullptr, nullptr, true);
+ return HandleIncludeDirective(HashLoc, ImportTok);
}
/// HandleIncludeMacrosDirective - The -imacros command line option turns into a
Modified: cfe/trunk/lib/Lex/Preprocessor.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/Preprocessor.cpp?rev=358231&r1=358230&r2=358231&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/Preprocessor.cpp (original)
+++ cfe/trunk/lib/Lex/Preprocessor.cpp Thu Apr 11 14:18:23 2019
@@ -866,6 +866,7 @@ void Preprocessor::Lex(Token &Result) {
// We loop here until a lex function returns a token; this avoids recursion.
bool ReturnedToken;
+ bool IsNewToken = true;
do {
switch (CurLexerKind) {
case CLK_Lexer:
@@ -875,12 +876,11 @@ void Preprocessor::Lex(Token &Result) {
ReturnedToken = CurTokenLexer->Lex(Result);
break;
case CLK_CachingLexer:
- CachingLex(Result);
+ CachingLex(Result, IsNewToken);
ReturnedToken = true;
break;
case CLK_LexAfterModuleImport:
- LexAfterModuleImport(Result);
- ReturnedToken = true;
+ ReturnedToken = LexAfterModuleImport(Result);
break;
}
} while (!ReturnedToken);
@@ -894,6 +894,47 @@ void Preprocessor::Lex(Token &Result) {
Result.setIdentifierInfo(nullptr);
}
+ // Update ImportSeqState to track our position within a C++20 import-seq
+ // if this token is being produced as a result of phase 4 of translation.
+ if (getLangOpts().CPlusPlusModules && LexLevel == 1 && IsNewToken) {
+ switch (Result.getKind()) {
+ case tok::l_paren: case tok::l_square: case tok::l_brace:
+ ImportSeqState.handleOpenBracket();
+ break;
+ case tok::r_paren: case tok::r_square:
+ ImportSeqState.handleCloseBracket();
+ break;
+ case tok::r_brace:
+ ImportSeqState.handleCloseBrace();
+ break;
+ case tok::semi:
+ ImportSeqState.handleSemi();
+ break;
+ case tok::header_name:
+ case tok::annot_header_unit:
+ ImportSeqState.handleHeaderName();
+ break;
+ case tok::kw_export:
+ ImportSeqState.handleExport();
+ break;
+ case tok::identifier:
+ if (Result.getIdentifierInfo()->isModulesImport()) {
+ ImportSeqState.handleImport();
+ if (ImportSeqState.afterImportSeq()) {
+ ModuleImportLoc = Result.getLocation();
+ ModuleImportPath.clear();
+ ModuleImportExpectsIdentifier = true;
+ CurLexerKind = CLK_LexAfterModuleImport;
+ }
+ break;
+ }
+ LLVM_FALLTHROUGH;
+ default:
+ ImportSeqState.handleMisc();
+ break;
+ }
+ }
+
LastTokenWasAt = Result.is(tok::at);
--LexLevel;
}
@@ -902,8 +943,8 @@ void Preprocessor::Lex(Token &Result) {
/// \p AllowConcatenation is \c true).
///
/// \param FilenameTok Filled in with the next token. On success, this will
-/// be either an angle_header_name or a string_literal token. On
-/// failure, it will be whatever other token was found instead.
+/// be either a header_name token. On failure, it will be whatever other
+/// token was found instead.
/// \param AllowMacroExpansion If \c true, allow the header name to be formed
/// by macro expansion (concatenating tokens as necessary if the first
/// token is a '<').
@@ -921,6 +962,10 @@ bool Preprocessor::LexHeaderName(Token &
// case, glue the tokens together into an angle_string_literal token.
SmallString<128> FilenameBuffer;
if (FilenameTok.is(tok::less) && AllowMacroExpansion) {
+ bool StartOfLine = FilenameTok.isAtStartOfLine();
+ bool LeadingSpace = FilenameTok.hasLeadingSpace();
+ bool LeadingEmptyMacro = FilenameTok.hasLeadingEmptyMacro();
+
SourceLocation Start = FilenameTok.getLocation();
SourceLocation End;
FilenameBuffer.push_back('<');
@@ -970,6 +1015,9 @@ bool Preprocessor::LexHeaderName(Token &
FilenameTok.startToken();
FilenameTok.setKind(tok::header_name);
+ FilenameTok.setFlagValue(Token::StartOfLine, StartOfLine);
+ FilenameTok.setFlagValue(Token::LeadingSpace, LeadingSpace);
+ FilenameTok.setFlagValue(Token::LeadingEmptyMacro, LeadingEmptyMacro);
CreateString(FilenameBuffer, FilenameTok, Start, End);
} else if (FilenameTok.is(tok::string_literal) && AllowMacroExpansion) {
// Convert a string-literal token of the form " h-char-sequence "
@@ -990,14 +1038,148 @@ bool Preprocessor::LexHeaderName(Token &
return false;
}
+/// Collect the tokens of a C++20 pp-import-suffix.
+void Preprocessor::CollectPpImportSuffix(SmallVectorImpl<Token> &Toks) {
+ // FIXME: For error recovery, consider recognizing attribute syntax here
+ // and terminating / diagnosing a missing semicolon if we find anything
+ // else? (Can we leave that to the parser?)
+ unsigned BracketDepth = 0;
+ while (true) {
+ Toks.emplace_back();
+ Lex(Toks.back());
+
+ switch (Toks.back().getKind()) {
+ case tok::l_paren: case tok::l_square: case tok::l_brace:
+ ++BracketDepth;
+ break;
+
+ case tok::r_paren: case tok::r_square: case tok::r_brace:
+ if (BracketDepth == 0)
+ return;
+ --BracketDepth;
+ break;
+
+ case tok::semi:
+ if (BracketDepth == 0)
+ return;
+ break;
+
+ case tok::eof:
+ return;
+
+ default:
+ break;
+ }
+ }
+}
+
+
/// Lex a token following the 'import' contextual keyword.
///
-void Preprocessor::LexAfterModuleImport(Token &Result) {
+/// pp-import: [C++20]
+/// import header-name pp-import-suffix[opt] ;
+/// import header-name-tokens pp-import-suffix[opt] ;
+/// [ObjC] @ import module-name ;
+/// [Clang] import module-name ;
+///
+/// header-name-tokens:
+/// string-literal
+/// < [any sequence of preprocessing-tokens other than >] >
+///
+/// module-name:
+/// module-name-qualifier[opt] identifier
+///
+/// module-name-qualifier
+/// module-name-qualifier[opt] identifier .
+///
+/// We respond to a pp-import by importing macros from the named module.
+bool Preprocessor::LexAfterModuleImport(Token &Result) {
// Figure out what kind of lexer we actually have.
recomputeCurLexerKind();
- // Lex the next token.
- Lex(Result);
+ // Lex the next token. The header-name lexing rules are used at the start of
+ // a pp-import.
+ //
+ // For now, we only support header-name imports in C++20 mode.
+ // FIXME: Should we allow this in all language modes that support an import
+ // declaration as an extension?
+ if (ModuleImportPath.empty() && getLangOpts().CPlusPlusModules) {
+ if (LexHeaderName(Result))
+ return true;
+ } else {
+ Lex(Result);
+ }
+
+ // Allocate a holding buffer for a sequence of tokens and introduce it into
+ // the token stream.
+ auto EnterTokens = [this](ArrayRef<Token> Toks) {
+ auto ToksCopy = llvm::make_unique<Token[]>(Toks.size());
+ std::copy(Toks.begin(), Toks.end(), ToksCopy.get());
+ EnterTokenStream(std::move(ToksCopy), Toks.size(),
+ /*DisableMacroExpansion*/ true);
+ };
+
+ // Check for a header-name.
+ SmallVector<Token, 32> Suffix;
+ if (Result.is(tok::header_name)) {
+ // Enter the header-name token into the token stream; a Lex action cannot
+ // both return a token and cache tokens (doing so would corrupt the token
+ // cache if the call to Lex comes from CachingLex / PeekAhead).
+ Suffix.push_back(Result);
+
+ // Consume the pp-import-suffix and expand any macros in it now. We'll add
+ // it back into the token stream later.
+ CollectPpImportSuffix(Suffix);
+ if (Suffix.back().isNot(tok::semi)) {
+ // This is not a pp-import after all.
+ EnterTokens(Suffix);
+ return false;
+ }
+
+ // C++2a [cpp.module]p1:
+ // The ';' preprocessing-token terminating a pp-import shall not have
+ // been produced by macro replacement.
+ SourceLocation SemiLoc = Suffix.back().getLocation();
+ if (SemiLoc.isMacroID())
+ Diag(SemiLoc, diag::err_header_import_semi_in_macro);
+
+ // Reconstitute the import token.
+ Token ImportTok;
+ ImportTok.startToken();
+ ImportTok.setKind(tok::kw_import);
+ ImportTok.setLocation(ModuleImportLoc);
+ ImportTok.setIdentifierInfo(getIdentifierInfo("import"));
+ ImportTok.setLength(6);
+
+ auto Action = HandleHeaderIncludeOrImport(
+ /*HashLoc*/ SourceLocation(), ImportTok, Suffix.front(), SemiLoc);
+ switch (Action.Kind) {
+ case ImportAction::None:
+ break;
+
+ case ImportAction::ModuleBegin:
+ // Let the parser know we're textually entering the module.
+ Suffix.emplace_back();
+ Suffix.back().startToken();
+ Suffix.back().setKind(tok::annot_module_begin);
+ Suffix.back().setLocation(SemiLoc);
+ Suffix.back().setAnnotationEndLoc(SemiLoc);
+ Suffix.back().setAnnotationValue(Action.ModuleForHeader);
+ LLVM_FALLTHROUGH;
+
+ case ImportAction::ModuleImport:
+ // We chose to import (or textually enter) the file. Convert the
+ // header-name token into a header unit annotation token.
+ Suffix[0].setKind(tok::annot_header_unit);
+ Suffix[0].setAnnotationEndLoc(Suffix[0].getLocation());
+ Suffix[0].setAnnotationValue(Action.ModuleForHeader);
+ // FIXME: Call the moduleImport callback?
+ break;
+ }
+
+ EnterTokens(Suffix);
+ return false;
+ }
// The token sequence
//
@@ -1012,7 +1194,7 @@ void Preprocessor::LexAfterModuleImport(
Result.getLocation()));
ModuleImportExpectsIdentifier = false;
CurLexerKind = CLK_LexAfterModuleImport;
- return;
+ return true;
}
// If we're expecting a '.' or a ';', and we got a '.', then wait until we
@@ -1021,40 +1203,61 @@ void Preprocessor::LexAfterModuleImport(
if (!ModuleImportExpectsIdentifier && Result.getKind() == tok::period) {
ModuleImportExpectsIdentifier = true;
CurLexerKind = CLK_LexAfterModuleImport;
- return;
+ return true;
}
- // If we have a non-empty module path, load the named module.
- if (!ModuleImportPath.empty()) {
- // Under the Modules TS, the dot is just part of the module name, and not
- // a real hierarchy separator. Flatten such module names now.
- //
- // FIXME: Is this the right level to be performing this transformation?
- std::string FlatModuleName;
- if (getLangOpts().ModulesTS) {
- for (auto &Piece : ModuleImportPath) {
- if (!FlatModuleName.empty())
- FlatModuleName += ".";
- FlatModuleName += Piece.first->getName();
- }
- SourceLocation FirstPathLoc = ModuleImportPath[0].second;
- ModuleImportPath.clear();
- ModuleImportPath.push_back(
- std::make_pair(getIdentifierInfo(FlatModuleName), FirstPathLoc));
- }
-
- Module *Imported = nullptr;
- if (getLangOpts().Modules) {
- Imported = TheModuleLoader.loadModule(ModuleImportLoc,
- ModuleImportPath,
- Module::Hidden,
- /*IsIncludeDirective=*/false);
- if (Imported)
- makeModuleVisible(Imported, ModuleImportLoc);
+ // If we didn't recognize a module name at all, this is not a (valid) import.
+ if (ModuleImportPath.empty() || Result.is(tok::eof))
+ return true;
+
+ // Consume the pp-import-suffix and expand any macros in it now, if we're not
+ // at the semicolon already.
+ SourceLocation SemiLoc = Result.getLocation();
+ if (Result.isNot(tok::semi)) {
+ Suffix.push_back(Result);
+ CollectPpImportSuffix(Suffix);
+ if (Suffix.back().isNot(tok::semi)) {
+ // This is not an import after all.
+ EnterTokens(Suffix);
+ return false;
+ }
+ SemiLoc = Suffix.back().getLocation();
+ }
+
+ // Under the Modules TS, the dot is just part of the module name, and not
+ // a real hierarchy separator. Flatten such module names now.
+ //
+ // FIXME: Is this the right level to be performing this transformation?
+ std::string FlatModuleName;
+ if (getLangOpts().ModulesTS || getLangOpts().CPlusPlusModules) {
+ for (auto &Piece : ModuleImportPath) {
+ if (!FlatModuleName.empty())
+ FlatModuleName += ".";
+ FlatModuleName += Piece.first->getName();
}
- if (Callbacks && (getLangOpts().Modules || getLangOpts().DebuggerSupport))
- Callbacks->moduleImport(ModuleImportLoc, ModuleImportPath, Imported);
+ SourceLocation FirstPathLoc = ModuleImportPath[0].second;
+ ModuleImportPath.clear();
+ ModuleImportPath.push_back(
+ std::make_pair(getIdentifierInfo(FlatModuleName), FirstPathLoc));
+ }
+
+ Module *Imported = nullptr;
+ if (getLangOpts().Modules) {
+ Imported = TheModuleLoader.loadModule(ModuleImportLoc,
+ ModuleImportPath,
+ Module::Hidden,
+ /*IsIncludeDirective=*/false);
+ if (Imported)
+ makeModuleVisible(Imported, SemiLoc);
+ }
+ if (Callbacks)
+ Callbacks->moduleImport(ModuleImportLoc, ModuleImportPath, Imported);
+
+ if (!Suffix.empty()) {
+ EnterTokens(Suffix);
+ return false;
}
+ return true;
}
void Preprocessor::makeModuleVisible(Module *M, SourceLocation Loc) {
Modified: cfe/trunk/lib/Lex/TokenConcatenation.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/TokenConcatenation.cpp?rev=358231&r1=358230&r2=358231&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/TokenConcatenation.cpp (original)
+++ cfe/trunk/lib/Lex/TokenConcatenation.cpp Thu Apr 11 14:18:23 2019
@@ -160,6 +160,11 @@ static char GetFirstChar(const Preproces
bool TokenConcatenation::AvoidConcat(const Token &PrevPrevTok,
const Token &PrevTok,
const Token &Tok) const {
+ // Conservatively assume that every annotation token that has a printable
+ // form requires whitespace.
+ if (PrevTok.isAnnotation())
+ return true;
+
// First, check to see if the tokens were directly adjacent in the original
// source. If they were, it must be okay to stick them together: if there
// were an issue, the tokens would have been lexed differently.
Added: cfe/trunk/test/CXX/cpp/cpp.module/Inputs/attrs.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/cpp/cpp.module/Inputs/attrs.h?rev=358231&view=auto
==============================================================================
--- cfe/trunk/test/CXX/cpp/cpp.module/Inputs/attrs.h (added)
+++ cfe/trunk/test/CXX/cpp/cpp.module/Inputs/attrs.h Thu Apr 11 14:18:23 2019
@@ -0,0 +1 @@
+#define ATTRS [[ ]]
Added: cfe/trunk/test/CXX/cpp/cpp.module/Inputs/empty.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/cpp/cpp.module/Inputs/empty.h?rev=358231&view=auto
==============================================================================
(empty)
Added: cfe/trunk/test/CXX/cpp/cpp.module/p1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/cpp/cpp.module/p1.cpp?rev=358231&view=auto
==============================================================================
--- cfe/trunk/test/CXX/cpp/cpp.module/p1.cpp (added)
+++ cfe/trunk/test/CXX/cpp/cpp.module/p1.cpp Thu Apr 11 14:18:23 2019
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -std=c++2a -emit-header-module -fmodule-name=attrs -x c++-header %S/Inputs/empty.h %S/Inputs/attrs.h -o %t.pcm
+// RUN: %clang_cc1 -std=c++2a %s -fmodule-file=%t.pcm -E -verify -I%S/Inputs | FileCheck %s
+
+#define SEMI ;
+// expected-error at +1 {{semicolon terminating header import declaration cannot be produced by a macro}}
+import "empty.h" SEMI // CHECK: import attrs.{{.*}};
+
+#define IMPORT import "empty.h"
+IMPORT; // CHECK: import attrs.{{.*}};
+
+#define IMPORT_ANGLED import <empty.h>
+IMPORT_ANGLED; // CHECK: import attrs.{{.*}};
+
+// Ensure that macros only become visible at the semicolon.
+// CHECK: import attrs.{{.*}} ATTRS ;
+import "attrs.h" ATTRS ;
+// CHECK: {{\[\[}} ]] int n;
+ATTRS int n;
Added: cfe/trunk/test/CXX/cpp/cpp.module/p2.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/cpp/cpp.module/p2.cpp?rev=358231&view=auto
==============================================================================
--- cfe/trunk/test/CXX/cpp/cpp.module/p2.cpp (added)
+++ cfe/trunk/test/CXX/cpp/cpp.module/p2.cpp Thu Apr 11 14:18:23 2019
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -std=c++2a -emit-header-module -fmodule-name=attrs -x c++-header %S/Inputs/empty.h %S/Inputs/attrs.h -o %t.pcm
+// RUN: %clang_cc1 -std=c++2a %s -fmodule-file=%t.pcm -fsyntax-only -verify -I%S/Inputs
+
+template<int> struct import; // expected-note 2{{previous}}
+constexpr struct { int h; } empty = {0};
+struct A;
+struct B;
+struct C;
+template<> struct import<0> {
+ static A a;
+ static B b;
+ static C c;
+};
+
+// OK, not an import-declaration.
+// FIXME: This is valid, see PR41192
+struct A {} // FIXME expected-error {{expected ';'}}
+::import
+<empty.h>::a; // FIXME expected-error {{requires a type specifier}}
+
+// This is invalid: the tokens after 'import' are a header-name, so cannot be
+// parsed as a template-argument-list.
+struct B {}
+import // expected-error {{redefinition of 'import'}} expected-error {{expected ';'}}
+<empty.h>::b; // (error recovery skips these tokens)
+
+// Likewise, this is ill-formed after the tokens are reconstituted into a
+// header-name token.
+struct C {}
+import // expected-error {{redefinition of 'import'}} expected-error {{expected ';'}}
+<
+empty.h // (error recovery skips these tokens)
+>::c;
Added: cfe/trunk/test/CXX/lex/lex.pptoken/Inputs/foo bar
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/lex/lex.pptoken/Inputs/foo%20%20bar?rev=358231&view=auto
==============================================================================
--- cfe/trunk/test/CXX/lex/lex.pptoken/Inputs/foo bar (added)
+++ cfe/trunk/test/CXX/lex/lex.pptoken/Inputs/foo bar Thu Apr 11 14:18:23 2019
@@ -0,0 +1 @@
+#error ERROR: This file should never actually be included
Added: cfe/trunk/test/CXX/lex/lex.pptoken/Inputs/foo bar
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/lex/lex.pptoken/Inputs/foo%20bar?rev=358231&view=auto
==============================================================================
--- cfe/trunk/test/CXX/lex/lex.pptoken/Inputs/foo bar (added)
+++ cfe/trunk/test/CXX/lex/lex.pptoken/Inputs/foo bar Thu Apr 11 14:18:23 2019
@@ -0,0 +1 @@
+#error ERROR: This file should never actually be included
Added: cfe/trunk/test/CXX/lex/lex.pptoken/p3-2a.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/lex/lex.pptoken/p3-2a.cpp?rev=358231&view=auto
==============================================================================
--- cfe/trunk/test/CXX/lex/lex.pptoken/p3-2a.cpp (added)
+++ cfe/trunk/test/CXX/lex/lex.pptoken/p3-2a.cpp Thu Apr 11 14:18:23 2019
@@ -0,0 +1,81 @@
+// RUN: not %clang_cc1 -std=c++2a -E -I%S/Inputs %s -o - | FileCheck %s --strict-whitespace --implicit-check-not=ERROR
+
+// Check for context-sensitive header-name token formation.
+// CHECK: import <foo bar>;
+import <foo bar>;
+
+// Not at the top level: these are each 8 tokens rather than 5.
+// CHECK: { import <foo bar>; }
+{ import <foo bar>; }
+// CHECK: ( import <foo bar>; :>
+( import <foo bar>; :>
+// CHECK: [ import <foo bar>; %>
+[ import <foo bar>; %>
+
+// CHECK: import <foo bar>;
+import <foo bar>;
+
+// CHECK: foo; import <foo bar>;
+foo; import <foo bar>;
+
+// CHECK: foo import <foo bar>;
+foo import <foo bar>;
+
+// CHECK: import <foo bar> {{\[\[ ]]}};
+import <foo bar> [[ ]];
+
+// CHECK: import <foo bar> import <foo bar>;
+import <foo bar> import <foo bar>;
+
+// FIXME: We do not form header-name tokens in the pp-import-suffix of a
+// pp-import. Conforming programs can't tell the difference.
+// CHECK: import <foo bar> {} import <foo bar>;
+// FIXME: import <foo bar> {} import <foo bar>;
+import <foo bar> {} import <foo bar>;
+
+
+// CHECK: export import <foo bar>;
+export import <foo bar>;
+
+// CHECK: export export import <foo bar>;
+export export import <foo bar>;
+
+#define UNBALANCED_PAREN (
+// CHECK: import <foo bar>;
+import <foo bar>;
+
+UNBALANCED_PAREN
+// CHECK: import <foo bar>;
+import <foo bar>;
+)
+
+_Pragma("clang no_such_pragma (");
+// CHECK: import <foo bar>;
+import <foo bar>;
+
+#define HEADER <foo bar>
+// CHECK: import <foo bar>;
+import HEADER;
+
+// CHECK: import <foo bar>;
+import <
+foo
+ bar
+>;
+
+// CHECK: import{{$}}
+// CHECK: {{^}}<foo bar>;
+import
+<
+foo
+ bar
+>;
+
+// CHECK: import{{$}}
+// CHECK: {{^}}<foo bar>;
+import
+<foo bar>;
+
+#define IMPORT import <foo bar>
+// CHECK: import <foo bar>;
+IMPORT;
Modified: cfe/trunk/test/Modules/framework-name.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/framework-name.m?rev=358231&r1=358230&r2=358231&view=diff
==============================================================================
--- cfe/trunk/test/Modules/framework-name.m (original)
+++ cfe/trunk/test/Modules/framework-name.m Thu Apr 11 14:18:23 2019
@@ -7,10 +7,10 @@
// Sanity check that we won't somehow find non-canonical module names or
// modules where we shouldn't search the framework.
-// RUN: echo '@import NameInModMap' | not %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t.mcp -F %S/Inputs -F %t -Wauto-import -x objective-c - 2>&1 | FileCheck %s
-// RUN: echo '@import NameInDir' | not %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t.mcp -F %S/Inputs -F %t -Wauto-import -x objective-c - 2>&1 | FileCheck %s
-// RUN: echo '@import NameInImport' | not %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t.mcp -F %S/Inputs -F %t -Wauto-import -x objective-c - 2>&1 | FileCheck %s
-// RUN: echo '@import NameInImportInferred' | not %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t.mcp -F %S/Inputs -F %t -Wauto-import -x objective-c - 2>&1 | FileCheck %s
+// RUN: echo '@import NameInModMap;' | not %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t.mcp -F %S/Inputs -F %t -Wauto-import -x objective-c - 2>&1 | FileCheck %s
+// RUN: echo '@import NameInDir;' | not %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t.mcp -F %S/Inputs -F %t -Wauto-import -x objective-c - 2>&1 | FileCheck %s
+// RUN: echo '@import NameInImport;' | not %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t.mcp -F %S/Inputs -F %t -Wauto-import -x objective-c - 2>&1 | FileCheck %s
+// RUN: echo '@import NameInImportInferred;' | not %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t.mcp -F %S/Inputs -F %t -Wauto-import -x objective-c - 2>&1 | FileCheck %s
// CHECK: module '{{.*}}' not found
// FIXME: We might want to someday lock down framework modules so that these
Modified: cfe/trunk/test/Modules/module_file_info.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/module_file_info.m?rev=358231&r1=358230&r2=358231&view=diff
==============================================================================
--- cfe/trunk/test/Modules/module_file_info.m (original)
+++ cfe/trunk/test/Modules/module_file_info.m Thu Apr 11 14:18:23 2019
@@ -21,7 +21,7 @@
// CHECK: Language options:
// CHECK: C99: Yes
// CHECK: Objective-C: Yes
-// CHECK: modules extension to C: Yes
+// CHECK: modules semantics: Yes
// CHECK: Module features:
// CHECK: myfeature
More information about the cfe-commits
mailing list