diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td index 5eceeced311f2..2ef13f568667d 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, DefaultIgnore; def ext_named_variadic_macro : Extension< "named variadic macros are a GNU extension">, InGroup; -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 0d684d5c7f9fe..f206d012eacc9 100644 --- a/clang/include/clang/Frontend/CompilerInstance.h +++ b/clang/include/clang/Frontend/CompilerInstance.h @@ -168,13 +168,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 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 c7e152a75f51f..8830294ea1658 100644 --- a/clang/include/clang/Lex/Preprocessor.h +++ b/clang/include/clang/Lex/Preprocessor.h @@ -381,12 +381,6 @@ class Preprocessor { llvm::DenseMap> 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; @@ -1857,7 +1851,6 @@ class Preprocessor { return FirstPPTokenLoc; } - bool LexAfterModuleImport(Token &Result); void CollectPPImportSuffix(SmallVectorImpl &Toks, bool StopUntilEOD = false); bool CollectPPImportSuffixAndEnterStream(SmallVectorImpl &Toks, @@ -2914,6 +2907,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. @@ -3177,9 +3171,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 33919bc1c4634..1f1b6701c38df 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -985,6 +985,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. @@ -1980,14 +1982,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. @@ -2163,8 +2166,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(); } @@ -2177,9 +2179,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 f2e0d52c2cbba..ede5d49860fa4 100644 --- a/clang/lib/Lex/DependencyDirectivesScanner.cpp +++ b/clang/lib/Lex/DependencyDirectivesScanner.cpp @@ -582,15 +582,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, @@ -952,10 +949,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) { @@ -970,6 +963,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 10246552bb13d..7a3d79e744ef2 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 @@ -4448,9 +4449,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 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; @@ -4612,6 +4632,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 b90c04776ff9e..a73ee1f7aa5cc 100644 --- a/clang/lib/Lex/PPDirectives.cpp +++ b/clang/lib/Lex/PPDirectives.cpp @@ -1316,9 +1316,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); @@ -1333,13 +1333,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.: @@ -1363,10 +1363,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(); @@ -1467,11 +1464,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); @@ -4195,9 +4197,6 @@ void Preprocessor::HandleCXXImportDirective(Token ImportTok) { llvm::SaveAndRestore SaveImportingCXXModules( this->ImportingCXXNamedModules, true); - if (LastExportKeyword.is(tok::kw_export)) - LastExportKeyword.startToken(); - Token Tok; if (LexHeaderName(Tok)) { if (Tok.isNot(tok::eod)) @@ -4338,13 +4337,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(); @@ -4448,3 +4441,57 @@ 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 DirToks{AtTok, ImportTok}; + SmallVector Path; + SourceLocation UseLoc = ImportTok.getLocation(); + ModuleImportLoc = ImportTok.getLocation(); + Token Tok; + Lex(Tok); + if (HandleModuleName(ImportTok.getIdentifierInfo()->getName(), UseLoc, Tok, + Path, DirToks, + /*AllowMacroExpansion=*/true, + /*IsPartition=*/false)) + 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); + + SourceLocation End = + DirToks.back().isNot(tok::eod) + ? CheckEndOfDirective(ImportTok.getIdentifierInfo()->getName(), + /*EnableMacros=*/false, &DirToks) + + : DirToks.pop_back_val().getLocation(); + + Module *Imported = nullptr; + if (getLangOpts().Modules) { + Imported = TheModuleLoader.loadModule(ModuleImportLoc, Path, Module::Hidden, + /*IsInclusionDirective=*/false); + if (Imported) + makeModuleVisible(Imported, End); + } + + 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 2cfefac1052a4..4f5423f0e9b79 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 NextTok = - CurLexer ? CurLexer->peekNextPPToken() : CurTokenLexer->peekNextPPToken(); + std::optional 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,77 +1394,6 @@ void Preprocessor::EnterModuleSuffixTokenStream(ArrayRef 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 Suffix; - SmallVector Path; - Lex(Result); - if (LexModuleNameContinue(Result, ModuleImportLoc, Suffix, Path, - /*AllowMacroExpansion=*/true, - /*IsPartition=*/false)) - 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(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/test/Modules/objc-at-import.m b/clang/test/Modules/objc-at-import.m new file mode 100644 index 0000000000000..98978df3c42e4 --- /dev/null +++ b/clang/test/Modules/objc-at-import.m @@ -0,0 +1,42 @@ +// RUN: rm -rf %t +// RUN: split-file %s %t +// +// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t/cache -fimplicit-module-maps \ +// RUN: -I%S/Inputs -verify -x objective-c %t/macro-module-name.m +// +// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t/cache -fimplicit-module-maps \ +// RUN: -I%S/Inputs -verify -x objective-c %t/macro-at-import.m +// +// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t/cache -fimplicit-module-maps \ +// RUN: -I%S/Inputs -verify -x objective-c %t/macro-func-import.m + +//--- macro-module-name.m +// expected-no-diagnostics +#define M dummy +@import M; + +#ifndef DUMMY_H +#error "macros from module not visible after @import with macro module name" +#endif + +void *p = &dummy1; + +//--- macro-at-import.m +#define imp @import +imp dummy; + +#ifdef DUMMY_H +#error "module should not be imported via macro-constructed @import" +#endif + +void *p = &dummy1; // expected-error {{use of undeclared identifier 'dummy1'}} + +//--- macro-func-import.m +#define IMPORT(X) @import X +IMPORT(dummy); + +#ifdef DUMMY_H +#error "module should not be imported via function-like macro @import" +#endif + +void *p = &dummy1; // expected-error {{use of undeclared identifier 'dummy1'}} diff --git a/clang/unittests/Lex/DependencyDirectivesScannerTest.cpp b/clang/unittests/Lex/DependencyDirectivesScannerTest.cpp index 2c51330957721..91bda85a43f57 100644 --- a/clang/unittests/Lex/DependencyDirectivesScannerTest.cpp +++ b/clang/unittests/Lex/DependencyDirectivesScannerTest.cpp @@ -640,7 +640,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--> {this,view(cached)} - CLK_LexAfterModuleImport [{Tok}] {PP,na} diff --git a/lldb/test/Shell/Expr/TestClangModuleLoadError_FromExpression.test b/lldb/test/Shell/Expr/TestClangModuleLoadError_FromExpression.test index b964e9b27e914..b863d3585b539 100644 --- a/lldb/test/Shell/Expr/TestClangModuleLoadError_FromExpression.test +++ b/lldb/test/Shell/Expr/TestClangModuleLoadError_FromExpression.test @@ -39,11 +39,14 @@ module bar { #--- commands.input run ## Make sure expression fails so the 'note' diagnostics get printed. -expr @import Foo; @import Bar +expr @import Foo +expr @import Bar expr @import foo # CHECK: error: while importing modules: # CHECK-NEXT: header search couldn't locate module 'Foo' +# +# CHECK: error: while importing modules: # CHECK-NEXT: header search couldn't locate module 'Bar' # # CHECK: expr @import foo