https://github.com/yronglin updated https://github.com/llvm/llvm-project/pull/157726
>From ee275f4109d953efe0eada061babe72e90d8f7c5 Mon Sep 17 00:00:00 2001 From: yronglin <[email protected]> Date: Sat, 21 Feb 2026 21:52:19 -0800 Subject: [PATCH 1/2] [clang] Add HandleModuleName to avoid redundant module name handling code Signed-off-by: yronglin <[email protected]> --- clang/include/clang/Lex/Preprocessor.h | 9 +++- clang/lib/Lex/PPDirectives.cpp | 73 ++++---------------------- clang/lib/Lex/Preprocessor.cpp | 34 +++++++++++- 3 files changed, 49 insertions(+), 67 deletions(-) diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h index b6e42a6151ac3..c97187a1a244f 100644 --- a/clang/include/clang/Lex/Preprocessor.h +++ b/clang/include/clang/Lex/Preprocessor.h @@ -1833,8 +1833,13 @@ class Preprocessor { bool LexModuleNameContinue(Token &Tok, SourceLocation UseLoc, SmallVectorImpl<Token> &Suffix, SmallVectorImpl<IdentifierLoc> &Path, - bool AllowMacroExpansion = true, - bool IsPartition = false); + bool IsPartition = false, + bool AllowMacroExpansion = true); + bool HandleModuleName(StringRef DirType, SourceLocation UseLoc, Token &Tok, + SmallVectorImpl<IdentifierLoc> &Path, + SmallVectorImpl<Token> &DirToks, + bool IsPartition = false, + bool AllowMacroExpansion = true); void EnterModuleSuffixTokenStream(ArrayRef<Token> Toks); void HandleCXXImportDirective(Token Import); void HandleCXXModuleDirective(Token Module); diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp index 4a854c213926b..66990454f7ea4 100644 --- a/clang/lib/Lex/PPDirectives.cpp +++ b/clang/lib/Lex/PPDirectives.cpp @@ -4207,7 +4207,7 @@ void Preprocessor::HandleCXXImportDirective(Token ImportTok) { SmallVector<IdentifierLoc, 2> Path; bool ImportingHeader = false; bool IsPartition = false; - std::string FlatName; + switch (Tok.getKind()) { case tok::header_name: ImportingHeader = true; @@ -4221,27 +4221,11 @@ void Preprocessor::HandleCXXImportDirective(Token ImportTok) { Lex(Tok); [[fallthrough]]; case tok::identifier: { - bool LeadingSpace = Tok.hasLeadingSpace(); - unsigned NumToksInDirective = DirToks.size(); - if (LexModuleNameContinue(Tok, UseLoc, DirToks, Path)) { - if (Tok.isNot(tok::eod)) - CheckEndOfDirective(ImportTok.getIdentifierInfo()->getName(), - /*EnableMacros=*/false, &DirToks); - EnterModuleSuffixTokenStream(DirToks); + if (HandleModuleName(ImportTok.getIdentifierInfo()->getName(), UseLoc, Tok, + Path, DirToks, IsPartition)) return; - } - - // Clean the module-name tokens and replace these tokens with - // annot_module_name. - DirToks.resize(NumToksInDirective); - ModuleNameLoc *NameLoc = ModuleNameLoc::Create(*this, Path); - DirToks.emplace_back(); - DirToks.back().setKind(tok::annot_module_name); - DirToks.back().setAnnotationRange(NameLoc->getRange()); - DirToks.back().setAnnotationValue(static_cast<void *>(NameLoc)); - DirToks.back().setFlagValue(Token::LeadingSpace, LeadingSpace); - DirToks.push_back(Tok); + std::string FlatName; bool IsValid = (IsPartition && ModuleDeclState.isNamedModule()) || !IsPartition; if (Callbacks && IsValid) { @@ -4382,57 +4366,20 @@ void Preprocessor::HandleCXXModuleDirective(Token ModuleTok) { DirToks.push_back(Tok); break; case tok::identifier: { - bool LeadingSpace = Tok.hasLeadingSpace(); - unsigned NumToksInDirective = DirToks.size(); - - // C++ [cpp.module]p3: Any preprocessing tokens after the module - // preprocessing token in the module directive are processed just as in - // normal text. - // - // P3034R1 Module Declarations Shouldn’t be Macros. - if (LexModuleNameContinue(Tok, UseLoc, DirToks, Path, - /*AllowMacroExpansion=*/false)) { - if (Tok.isNot(tok::eod)) - CheckEndOfDirective(ModuleTok.getIdentifierInfo()->getName(), - /*EnableMacros=*/false, &DirToks); - EnterModuleSuffixTokenStream(DirToks); + if (HandleModuleName(ModuleTok.getIdentifierInfo()->getName(), UseLoc, Tok, + Path, DirToks, /*IsPartition=*/false, + /*AllowMacroExpansion=*/false)) return; - } - - ModuleNameLoc *NameLoc = ModuleNameLoc::Create(*this, Path); - DirToks.resize(NumToksInDirective); - DirToks.emplace_back(); - DirToks.back().setKind(tok::annot_module_name); - DirToks.back().setAnnotationRange(NameLoc->getRange()); - DirToks.back().setAnnotationValue(static_cast<void *>(NameLoc)); - DirToks.back().setFlagValue(Token::LeadingSpace, LeadingSpace); - DirToks.push_back(Tok); // C++20 [cpp.module]p // The pp-tokens, if any, of a pp-module shall be of the form: // pp-module-name pp-module-partition[opt] pp-tokens[opt] if (Tok.is(tok::colon)) { - NumToksInDirective = DirToks.size(); LexUnexpandedToken(Tok); - LeadingSpace = Tok.hasLeadingSpace(); - if (LexModuleNameContinue(Tok, UseLoc, DirToks, Partition, - /*AllowMacroExpansion=*/false, - /*IsPartition=*/true)) { - if (Tok.isNot(tok::eod)) - CheckEndOfDirective(ModuleTok.getIdentifierInfo()->getName(), - /*EnableMacros=*/false, &DirToks); - EnterModuleSuffixTokenStream(DirToks); + if (HandleModuleName(ModuleTok.getIdentifierInfo()->getName(), UseLoc, + Tok, Partition, DirToks, /*IsPartition=*/true, + /*AllowMacroExpansion=*/false)) return; - } - - ModuleNameLoc *PartitionLoc = ModuleNameLoc::Create(*this, Partition); - DirToks.resize(NumToksInDirective); - DirToks.emplace_back(); - DirToks.back().setKind(tok::annot_module_name); - DirToks.back().setAnnotationRange(NameLoc->getRange()); - DirToks.back().setAnnotationValue(static_cast<void *>(PartitionLoc)); - DirToks.back().setFlagValue(Token::LeadingSpace, LeadingSpace); - DirToks.push_back(Tok); } // If the current token is a macro definition, put it back to token stream diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp index a531f51408dae..44d4471015dd4 100644 --- a/clang/lib/Lex/Preprocessor.cpp +++ b/clang/lib/Lex/Preprocessor.cpp @@ -1205,8 +1205,8 @@ ModuleNameLoc *ModuleNameLoc::Create(Preprocessor &PP, ModuleIdPath Path) { bool Preprocessor::LexModuleNameContinue(Token &Tok, SourceLocation UseLoc, SmallVectorImpl<Token> &Suffix, SmallVectorImpl<IdentifierLoc> &Path, - bool AllowMacroExpansion, - bool IsPartition) { + bool IsPartition, + bool AllowMacroExpansion) { auto ConsumeToken = [&]() { if (AllowMacroExpansion) Lex(Tok); @@ -1250,6 +1250,36 @@ bool Preprocessor::LexModuleNameContinue(Token &Tok, SourceLocation UseLoc, } } +bool Preprocessor::HandleModuleName(StringRef DirType, SourceLocation UseLoc, + Token &Tok, + SmallVectorImpl<IdentifierLoc> &Path, + SmallVectorImpl<Token> &DirToks, + bool IsPartition, + bool AllowMacroExpansion) { + bool LeadingSpace = Tok.hasLeadingSpace(); + unsigned NumToksInDirective = DirToks.size(); + if (LexModuleNameContinue(Tok, UseLoc, DirToks, Path, IsPartition, + AllowMacroExpansion)) { + if (Tok.isNot(tok::eod)) + CheckEndOfDirective(DirType, + /*EnableMacros=*/false, &DirToks); + EnterModuleSuffixTokenStream(DirToks); + return true; + } + + // Clean the module-name tokens and replace these tokens with + // annot_module_name. + DirToks.resize(NumToksInDirective); + ModuleNameLoc *NameLoc = ModuleNameLoc::Create(*this, Path); + DirToks.emplace_back(); + DirToks.back().setKind(tok::annot_module_name); + DirToks.back().setAnnotationRange(NameLoc->getRange()); + DirToks.back().setAnnotationValue(static_cast<void *>(NameLoc)); + DirToks.back().setFlagValue(Token::LeadingSpace, LeadingSpace); + DirToks.push_back(Tok); + return false; +} + /// [cpp.pre]/p2: /// A preprocessing directive consists of a sequence of preprocessing tokens /// that satisfies the following constraints: At the start of translation phase >From b42cd940e0b6467ef334c66b9925fb0045087f61 Mon Sep 17 00:00:00 2001 From: yronglin <[email protected]> Date: Fri, 27 Feb 2026 07:23:23 -0800 Subject: [PATCH 2/2] [ObjC][Preprocessor] Handle @import directive as a pp-directive Signed-off-by: yronglin <[email protected]> --- .../include/clang/Basic/DiagnosticLexKinds.td | 2 +- .../include/clang/Frontend/CompilerInstance.h | 11 +-- clang/include/clang/Lex/Preprocessor.h | 11 +-- clang/lib/Frontend/CompilerInstance.cpp | 27 ++--- clang/lib/Lex/DependencyDirectivesScanner.cpp | 18 ++-- clang/lib/Lex/Lexer.cpp | 36 ++++++- clang/lib/Lex/PPDirectives.cpp | 99 ++++++++++++++----- clang/lib/Lex/PPLexerChange.cpp | 13 +-- clang/lib/Lex/Preprocessor.cpp | 91 +---------------- clang/test/Modules/lookup.cpp | 7 +- clang/test/Modules/no-stale-modtime.m | 3 +- .../Lex/DependencyDirectivesScannerTest.cpp | 2 +- clang/utils/ClangVisualizers/clang.natvis | 1 - 13 files changed, 146 insertions(+), 175 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td index 77feea9f869e9..d88aa891dc3e5 100644 --- a/clang/include/clang/Basic/DiagnosticLexKinds.td +++ b/clang/include/clang/Basic/DiagnosticLexKinds.td @@ -503,7 +503,7 @@ def warn_cxx98_compat_variadic_macro : Warning< InGroup<CXX98CompatPedantic>, DefaultIgnore; def ext_named_variadic_macro : Extension< "named variadic macros are a GNU extension">, InGroup<VariadicMacros>; -def err_embedded_directive : Error<"embedding a %select{#|C++ }0%1 directive " +def err_embedded_directive : Error<"embedding a %select{|#}0%1 directive " "within macro arguments is not supported">; def ext_embedded_directive : Extension< "embedding a directive within macro arguments has undefined behavior">, diff --git a/clang/include/clang/Frontend/CompilerInstance.h b/clang/include/clang/Frontend/CompilerInstance.h index 217efa3fe756e..fa811ae4fe8b2 100644 --- a/clang/include/clang/Frontend/CompilerInstance.h +++ b/clang/include/clang/Frontend/CompilerInstance.h @@ -167,13 +167,10 @@ class CompilerInstance : public ModuleLoader { /// Should we delete the BuiltModules when we're done? bool DeleteBuiltModules = true; - /// The location of the module-import keyword for the last module - /// import. - SourceLocation LastModuleImportLoc; - - /// The result of the last module import. - /// - ModuleLoadResult LastModuleImportResult; + /// Cache of module import results keyed by import location. + /// It is important to eliminate redundant diagnostics + /// when both the preprocessor and parser see the same import declaration. + llvm::SmallDenseMap<SourceLocation, ModuleLoadResult, 4> ModuleImportResults; /// Whether we should (re)build the global module index once we /// have finished with this translation unit. diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h index c97187a1a244f..1e0b51eb7e7b4 100644 --- a/clang/include/clang/Lex/Preprocessor.h +++ b/clang/include/clang/Lex/Preprocessor.h @@ -381,12 +381,6 @@ class Preprocessor { llvm::DenseMap<FileID, SmallVector<const char *>> CheckPoints; unsigned CheckPointCounter = 0; - /// Whether the import is an `@import` or a standard c++ modules import. - bool IsAtImport = false; - - /// Whether the last token we lexed was an '@'. - bool LastTokenWasAt = false; - /// Whether we're importing a standard C++20 named Modules. bool ImportingCXXNamedModules = false; @@ -1859,7 +1853,6 @@ class Preprocessor { return FirstPPTokenLoc; } - bool LexAfterModuleImport(Token &Result); void CollectPPImportSuffix(SmallVectorImpl<Token> &Toks, bool StopUntilEOD = false); bool CollectPPImportSuffixAndEnterStream(SmallVectorImpl<Token> &Toks, @@ -2916,6 +2909,7 @@ class Preprocessor { void HandleIncludeMacrosDirective(SourceLocation HashLoc, Token &Tok); void HandleImportDirective(SourceLocation HashLoc, Token &Tok); void HandleMicrosoftImportDirective(Token &Tok); + void HandleObjCImportDirective(Token &AtTok, Token &ImportTok); public: /// Check that the given module is available, producing a diagnostic if not. @@ -3179,9 +3173,6 @@ class Preprocessor { static bool CLK_DependencyDirectivesLexer(Preprocessor &P, Token &Result) { return P.CurLexer->LexDependencyDirectiveToken(Result); } - static bool CLK_LexAfterModuleImport(Preprocessor &P, Token &Result) { - return P.LexAfterModuleImport(Result); - } }; /// Abstract base class that describes a handler that will receive diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index 9f1a3c56feec1..f282863e7cb80 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -1003,6 +1003,8 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) { if (hasSourceManager() && !Act.isModelParsingAction()) getSourceManager().clearIDTables(); + ModuleImportResults.clear(); + if (Act.BeginSourceFile(*this, FIF)) { if (llvm::Error Err = Act.Execute()) { consumeError(std::move(Err)); // FIXME this drops errors on the floor. @@ -1955,14 +1957,15 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, SourceLocation ModuleNameLoc = Path[0].getLoc(); // If we've already handled this import, just return the cached result. - // This one-element cache is important to eliminate redundant diagnostics - // when both the preprocessor and parser see the same import declaration. - if (ImportLoc.isValid() && LastModuleImportLoc == ImportLoc) { - // Make the named module visible. - if (LastModuleImportResult && ModuleName != getLangOpts().CurrentModule) - TheASTReader->makeModuleVisible(LastModuleImportResult, Visibility, - ImportLoc); - return LastModuleImportResult; + // This cache eliminates redundant diagnostics when both the preprocessor + // and parser see the same import declaration. + if (ImportLoc.isValid()) { + auto CacheIt = ModuleImportResults.find(ImportLoc); + if (CacheIt != ModuleImportResults.end()) { + if (CacheIt->second && ModuleName != getLangOpts().CurrentModule) + TheASTReader->makeModuleVisible(CacheIt->second, Visibility, ImportLoc); + return CacheIt->second; + } } // If we don't already have information on this module, load the module now. @@ -2138,8 +2141,7 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, *Module, getDiagnostics())) { getDiagnostics().Report(ImportLoc, diag::note_module_import_here) << SourceRange(Path.front().getLoc(), Path.back().getLoc()); - LastModuleImportLoc = ImportLoc; - LastModuleImportResult = ModuleLoadResult(); + ModuleImportResults[ImportLoc] = ModuleLoadResult(); return ModuleLoadResult(); } @@ -2152,9 +2154,8 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, .getModuleMap() .resolveLinkAsDependencies(Module->getTopLevelModule()); - LastModuleImportLoc = ImportLoc; - LastModuleImportResult = ModuleLoadResult(Module); - return LastModuleImportResult; + ModuleImportResults[ImportLoc] = ModuleLoadResult(Module); + return ModuleLoadResult(Module); } void CompilerInstance::createModuleFromSource(SourceLocation ImportLoc, diff --git a/clang/lib/Lex/DependencyDirectivesScanner.cpp b/clang/lib/Lex/DependencyDirectivesScanner.cpp index 8320b3ddbca31..f31c76f9f675b 100644 --- a/clang/lib/Lex/DependencyDirectivesScanner.cpp +++ b/clang/lib/Lex/DependencyDirectivesScanner.cpp @@ -581,15 +581,12 @@ bool Scanner::lexModuleDirectiveBody(DirectiveKind Kind, const char *&First, return false; } + const auto &Tok = lexToken(First, End); pushDirective(Kind); - skipWhitespace(First, End); - if (First == End) + if (Tok.is(tok::eof) || Tok.is(tok::eod)) return false; - if (!isVerticalWhitespace(*First)) - return reportError( - DirectiveLoc, diag::err_dep_source_scanner_unexpected_tokens_at_import); - skipNewline(First, End); - return false; + return reportError(DirectiveLoc, + diag::err_dep_source_scanner_unexpected_tokens_at_import); } dependency_directives_scan::Token &Scanner::lexToken(const char *&First, @@ -951,10 +948,6 @@ bool Scanner::lexPPLine(const char *&First, const char *const End) { CurDirToks.clear(); }); - // FIXME: Shoule we handle @import as a preprocessing directive? - if (*First == '@') - return lexAt(First, End); - bool IsPreprocessedModule = isStartWithPreprocessedModuleDirective(First, End); if (*First == '_' && !IsPreprocessedModule) { @@ -969,6 +962,9 @@ bool Scanner::lexPPLine(const char *&First, const char *const End) { llvm::scope_exit ScEx2( [&]() { TheLexer.setParsingPreprocessorDirective(false); }); + if (*First == '@') + return lexAt(First, End); + // Handle module directives for C++20 modules. if (*First == 'i' || *First == 'e' || *First == 'm' || IsPreprocessedModule) return lexModule(First, End); diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp index 92c3046a6fd19..3e4548d76b140 100644 --- a/clang/lib/Lex/Lexer.cpp +++ b/clang/lib/Lex/Lexer.cpp @@ -34,6 +34,7 @@ #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/MemoryBufferRef.h" #include "llvm/Support/NativeFormatting.h" +#include "llvm/Support/SaveAndRestore.h" #include "llvm/Support/Unicode.h" #include "llvm/Support/UnicodeCharRanges.h" #include <algorithm> @@ -4436,9 +4437,28 @@ bool Lexer::LexTokenInternal(Token &Result) { case '@': // Objective C support. - if (CurPtr[-1] == '@' && LangOpts.ObjC) - Kind = tok::at; - else + if (CurPtr[-1] == '@' && LangOpts.ObjC) { + FormTokenWithChars(Result, CurPtr, tok::at); + if (PP && Result.isAtPhysicalStartOfLine() && !LexingRawMode && + !Is_PragmaLexer) { + Token NextPPTok; + NextPPTok.startToken(); + { + llvm::SaveAndRestore<bool> SavedParsingPreprocessorDirective( + this->ParsingPreprocessorDirective, true); + auto NextTokOr = peekNextPPToken(); + if (NextTokOr.has_value()) { + NextPPTok = *NextTokOr; + } + } + if (NextPPTok.is(tok::raw_identifier) && + NextPPTok.getRawIdentifier() == "import") { + PP->HandleDirective(Result); + return false; + } + } + return true; + } else Kind = tok::unknown; break; @@ -4600,6 +4620,16 @@ bool Lexer::LexDependencyDirectiveToken(Token &Result) { return true; return false; } + if (Result.is(tok::at) && Result.isAtStartOfLine()) { + auto NextTok = peekNextPPToken(); + if (NextTok && NextTok->is(tok::raw_identifier) && + NextTok->getRawIdentifier() == "import") { + PP->HandleDirective(Result); + if (PP->hadModuleLoaderFatalFailure()) + return true; + return false; + } + } if (Result.is(tok::raw_identifier)) { Result.setRawIdentifierData(TokPtr); if (!isLexingRawMode()) { diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp index 66990454f7ea4..3f2e66e66a458 100644 --- a/clang/lib/Lex/PPDirectives.cpp +++ b/clang/lib/Lex/PPDirectives.cpp @@ -1313,9 +1313,9 @@ void Preprocessor::HandleSkippedDirectiveWhileUsingPCH(Token &Result, void Preprocessor::HandleDirective(Token &Result) { // FIXME: Traditional: # with whitespace before it not recognized by K&R? - // We just parsed a # character at the start of a line, so we're in directive - // mode. Tell the lexer this so any newlines we see will be converted into an - // EOD token (which terminates the directive). + // We just parsed a # or @ character at the start of a line, so we're in + // directive mode. Tell the lexer this so any newlines we see will be + // converted into an EOD token (which terminates the directive). CurPPLexer->ParsingPreprocessorDirective = true; if (CurLexer) CurLexer->SetKeepWhitespaceMode(false); @@ -1330,13 +1330,13 @@ void Preprocessor::HandleDirective(Token &Result) { // pp-directive. bool ReadAnyTokensBeforeDirective =CurPPLexer->MIOpt.getHasReadAnyTokensVal(); - // Save the directive-introducing token('#' and import/module in C++20) in - // case we need to return it later. + // Save the directive-introducing token ('#', '@', or import/module in C++20) + // in case we need to return it later. Token Introducer = Result; // Read the next token, the directive flavor. This isn't expanded due to // C99 6.10.3p8. - if (Introducer.is(tok::hash)) + if (Introducer.isOneOf(tok::hash, tok::at)) LexUnexpandedToken(Result); // C99 6.10.3p11: Is this preprocessor directive in macro invocation? e.g.: @@ -1360,10 +1360,7 @@ void Preprocessor::HandleDirective(Token &Result) { case tok::pp___preprocessed_module: case tok::pp___preprocessed_import: Diag(Result, diag::err_embedded_directive) - << (getLangOpts().CPlusPlusModules && - Introducer.isModuleContextualKeyword( - /*AllowExport=*/false)) - << II->getName(); + << Introducer.is(tok::hash) << II->getName(); Diag(*ArgMacro, diag::note_macro_expansion_here) << ArgMacro->getIdentifierInfo(); DiscardUntilEndOfDirective(); @@ -1464,11 +1461,16 @@ void Preprocessor::HandleDirective(Token &Result) { return HandleCXXImportDirective(Result); // GNU Extensions. case tok::pp_import: - if (getLangOpts().CPlusPlusModules && - Introducer.isModuleContextualKeyword( - /*AllowExport=*/false)) + switch (Introducer.getKind()) { + case tok::hash: + return HandleImportDirective(Introducer.getLocation(), Result); + case tok::at: + return HandleObjCImportDirective(Introducer, Result); + case tok::kw_import: return HandleCXXImportDirective(Result); - return HandleImportDirective(Introducer.getLocation(), Result); + default: + llvm_unreachable("not a valid import directive"); + } case tok::pp_include_next: return HandleIncludeNextDirective(Introducer.getLocation(), Result); @@ -4192,9 +4194,6 @@ void Preprocessor::HandleCXXImportDirective(Token ImportTok) { llvm::SaveAndRestore<bool> SaveImportingCXXModules( this->ImportingCXXNamedModules, true); - if (LastExportKeyword.is(tok::kw_export)) - LastExportKeyword.startToken(); - Token Tok; if (LexHeaderName(Tok)) { if (Tok.isNot(tok::eod)) @@ -4334,13 +4333,7 @@ void Preprocessor::HandleCXXImportDirective(Token ImportTok) { /// The lexed module name are replaced by annot_module_name token. void Preprocessor::HandleCXXModuleDirective(Token ModuleTok) { assert(getLangOpts().CPlusPlusModules && ModuleTok.is(tok::kw_module)); - Token Introducer = ModuleTok; - if (LastExportKeyword.is(tok::kw_export)) { - Introducer = LastExportKeyword; - LastExportKeyword.startToken(); - } - - SourceLocation StartLoc = Introducer.getLocation(); + SourceLocation StartLoc = ModuleTok.getLocation(); Token Tok; SourceLocation UseLoc = ModuleTok.getLocation(); @@ -4444,3 +4437,61 @@ void Preprocessor::HandleCXXModuleDirective(Token ModuleTok) { } EnterModuleSuffixTokenStream(DirToks); } + +/// Lex a token following the 'import' contextual keyword. +/// +/// pp-import: +/// [ObjC] @ import module-name ; +/// +/// 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. +void Preprocessor::HandleObjCImportDirective(Token &AtTok, Token &ImportTok) { + assert(getLangOpts().ObjC && AtTok.is(tok::at) && + ImportTok.isObjCAtKeyword(tok::objc_import)); + ImportTok.setKind(tok::kw_import); + SmallVector<Token, 32> DirToks{AtTok, ImportTok}; + SmallVector<IdentifierLoc, 3> Path; + SourceLocation UseLoc = ImportTok.getLocation(); + ModuleImportLoc = ImportTok.getLocation(); + Token Tok; + Lex(Tok); + if (HandleModuleName(ImportTok.getIdentifierInfo()->getName(), UseLoc, Tok, + Path, DirToks, /*IsPartition=*/false, + /*AllowMacroExpansion=*/true)) + return; + + // Consume the pp-import-suffix and expand any macros in it now, if we're not + // at the semicolon already. + if (!DirToks.back().isOneOf(tok::semi, tok::eod)) + CollectPPImportSuffix(DirToks); + + if (DirToks.back().isNot(tok::eod)) + CheckEndOfDirective(ImportTok.getIdentifierInfo()->getName()); + else + DirToks.pop_back(); + + // This is not a pp-import after all. + if (DirToks.back().isNot(tok::semi)) { + EnterModuleSuffixTokenStream(DirToks); + return; + } + + Module *Imported = nullptr; + SourceLocation SemiLoc = DirToks.back().getLocation(); + if (getLangOpts().Modules) { + Imported = TheModuleLoader.loadModule(ModuleImportLoc, Path, Module::Hidden, + /*IsInclusionDirective=*/false); + if (Imported) + makeModuleVisible(Imported, SemiLoc); + } + + if (Callbacks) + Callbacks->moduleImport(ModuleImportLoc, Path, Imported); + + EnterModuleSuffixTokenStream(DirToks); +} diff --git a/clang/lib/Lex/PPLexerChange.cpp b/clang/lib/Lex/PPLexerChange.cpp index 05affedd48a86..35fc23092dcc1 100644 --- a/clang/lib/Lex/PPLexerChange.cpp +++ b/clang/lib/Lex/PPLexerChange.cpp @@ -115,10 +115,9 @@ void Preprocessor::EnterSourceFileWithLexer(Lexer *TheLexer, CurPPLexer = TheLexer; CurDirLookup = CurDir; CurLexerSubmodule = nullptr; - if (CurLexerCallback != CLK_LexAfterModuleImport) - CurLexerCallback = TheLexer->isDependencyDirectivesLexer() - ? CLK_DependencyDirectivesLexer - : CLK_Lexer; + CurLexerCallback = TheLexer->isDependencyDirectivesLexer() + ? CLK_DependencyDirectivesLexer + : CLK_Lexer; // Notify the client, if desired, that we are in a new source file. if (Callbacks && !CurLexer->Is_PragmaLexer) { @@ -154,8 +153,7 @@ void Preprocessor::EnterMacro(Token &Tok, SourceLocation ILEnd, PushIncludeMacroStack(); CurDirLookup = nullptr; CurTokenLexer = std::move(TokLexer); - if (CurLexerCallback != CLK_LexAfterModuleImport) - CurLexerCallback = CLK_TokenLexer; + CurLexerCallback = CLK_TokenLexer; } /// EnterTokenStream - Add a "macro" context to the top of the include stack, @@ -209,8 +207,7 @@ void Preprocessor::EnterTokenStream(const Token *Toks, unsigned NumToks, PushIncludeMacroStack(); CurDirLookup = nullptr; CurTokenLexer = std::move(TokLexer); - if (CurLexerCallback != CLK_LexAfterModuleImport) - CurLexerCallback = CLK_TokenLexer; + CurLexerCallback = CLK_TokenLexer; } /// Compute the relative path that names the given file relative to diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp index 44d4471015dd4..a1641fdc50ece 100644 --- a/clang/lib/Lex/Preprocessor.cpp +++ b/clang/lib/Lex/Preprocessor.cpp @@ -889,23 +889,6 @@ bool Preprocessor::HandleIdentifier(Token &Identifier) { return hadModuleLoaderFatalFailure(); } - // If this is the 'import' contextual keyword following an '@', note - // that the next token indicates a module name. - // - // Note that we do not treat 'import' as a contextual - // keyword when we're in a caching lexer, because caching lexers only get - // used in contexts where import declarations are disallowed. - // - // Likewise if this is the standard C++ import keyword. - if (((LastTokenWasAt && II.isImportKeyword()) || - Identifier.is(tok::kw_import)) && - !InMacroArgs && - (!DisableMacroExpansion || MacroExpansionInDirectivesOverride) && - CurLexerCallback != CLK_CachingLexer) { - ModuleImportLoc = Identifier.getLocation(); - IsAtImport = true; - CurLexerCallback = CLK_LexAfterModuleImport; - } return true; } @@ -1005,7 +988,6 @@ void Preprocessor::Lex(Token &Result) { CheckPointCounter = 0; } - LastTokenWasAt = Result.is(tok::at); if (Result.isNot(tok::kw_export)) LastExportKeyword.startToken(); @@ -1344,8 +1326,7 @@ bool Preprocessor::HandleModuleContextualKeyword(Token &Result) { CurPPLexer->ParsingFilename, Result.getIdentifierInfo()->isImportKeyword()); - std::optional<Token> NextTok = - CurLexer ? CurLexer->peekNextPPToken() : CurTokenLexer->peekNextPPToken(); + std::optional<Token> NextTok = peekNextPPToken(); if (!NextTok) return false; @@ -1357,7 +1338,6 @@ bool Preprocessor::HandleModuleContextualKeyword(Token &Result) { tok::header_name)) { Result.setKind(tok::kw_import); ModuleImportLoc = Result.getLocation(); - IsAtImport = false; return true; } } @@ -1414,75 +1394,6 @@ void Preprocessor::EnterModuleSuffixTokenStream(ArrayRef<Token> Toks) { CurTokenLexer->setLexingCXXModuleDirective(); } -/// Lex a token following the 'import' contextual keyword. -/// -/// 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(); - - SmallVector<Token, 32> Suffix; - SmallVector<IdentifierLoc, 3> Path; - Lex(Result); - if (LexModuleNameContinue(Result, ModuleImportLoc, Suffix, Path)) - return CollectPPImportSuffixAndEnterStream(Suffix); - - ModuleNameLoc *NameLoc = ModuleNameLoc::Create(*this, Path); - Suffix.clear(); - Suffix.emplace_back(); - Suffix.back().setKind(tok::annot_module_name); - Suffix.back().setAnnotationRange(NameLoc->getRange()); - Suffix.back().setAnnotationValue(static_cast<void *>(NameLoc)); - Suffix.push_back(Result); - - // 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 (Suffix.back().isNot(tok::semi)) { - if (Suffix.back().isNot(tok::eof)) - CollectPPImportSuffix(Suffix); - if (Suffix.back().isNot(tok::semi)) { - // This is not an import after all. - EnterModuleSuffixTokenStream(Suffix); - return false; - } - SemiLoc = Suffix.back().getLocation(); - } - - Module *Imported = nullptr; - if (getLangOpts().Modules) { - Imported = TheModuleLoader.loadModule(ModuleImportLoc, Path, Module::Hidden, - /*IsInclusionDirective=*/false); - if (Imported) - makeModuleVisible(Imported, SemiLoc); - } - - if (Callbacks) - Callbacks->moduleImport(ModuleImportLoc, Path, Imported); - - if (!Suffix.empty()) { - EnterModuleSuffixTokenStream(Suffix); - return false; - } - return true; -} - void Preprocessor::makeModuleVisible(Module *M, SourceLocation Loc, bool IncludeExports) { CurSubmoduleState->VisibleModules.setVisible( diff --git a/clang/test/Modules/lookup.cpp b/clang/test/Modules/lookup.cpp index 95c30bf3eedff..6e2e403df8814 100644 --- a/clang/test/Modules/lookup.cpp +++ b/clang/test/Modules/lookup.cpp @@ -1,9 +1,6 @@ -#define import @import -import lookup_left_cxx; -#undef import -#define IMPORT(X) @import X -IMPORT(lookup_right_cxx); +@import lookup_left_cxx; +@import lookup_right_cxx; // expected-warning@Inputs/lookup_left.hpp:3 {{weak identifier 'weak_identifier' never declared}} diff --git a/clang/test/Modules/no-stale-modtime.m b/clang/test/Modules/no-stale-modtime.m index aa16eb1db5f68..60b47487f448a 100644 --- a/clang/test/Modules/no-stale-modtime.m +++ b/clang/test/Modules/no-stale-modtime.m @@ -23,7 +23,8 @@ // RUN: -I %t -fsyntax-only %t/main.m -Rmodule-build -verify //--- b.h -@import l; @import r; +@import l; +@import r; //--- l.h @import t; // fromt l diff --git a/clang/unittests/Lex/DependencyDirectivesScannerTest.cpp b/clang/unittests/Lex/DependencyDirectivesScannerTest.cpp index 79e2832798917..9b20c328c918c 100644 --- a/clang/unittests/Lex/DependencyDirectivesScannerTest.cpp +++ b/clang/unittests/Lex/DependencyDirectivesScannerTest.cpp @@ -639,7 +639,7 @@ TEST(MinimizeSourceToDependencyDirectivesTest, AtImport) { ASSERT_FALSE(minimizeSourceToDependencyDirectives(" @ import A;\n", Out)); EXPECT_STREQ("@import A;\n", Out.data()); - ASSERT_FALSE(minimizeSourceToDependencyDirectives("@import A\n;", Out)); + ASSERT_FALSE(minimizeSourceToDependencyDirectives("@import A;\n", Out)); EXPECT_STREQ("@import A;\n", Out.data()); ASSERT_FALSE(minimizeSourceToDependencyDirectives("@import A.B;\n", Out)); diff --git a/clang/utils/ClangVisualizers/clang.natvis b/clang/utils/ClangVisualizers/clang.natvis index 0755f0ffcbf56..828557b7279b9 100644 --- a/clang/utils/ClangVisualizers/clang.natvis +++ b/clang/utils/ClangVisualizers/clang.natvis @@ -807,7 +807,6 @@ For later versions of Visual Studio, no setup is required--> <DisplayString Condition="IncludeMacroStack._Mypair._Myval2._Mylast - IncludeMacroStack._Mypair._Myval2._Myfirst"> {this,view(cached)} </DisplayString> - <DisplayString>CLK_LexAfterModuleImport</DisplayString> </Type> <Type Name="clang::Parser"> <DisplayString>[{Tok}] {PP,na}</DisplayString> _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
