From 26297f57634994b4ae47a0774c372d6944265bb2 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Fri, 15 Nov 2013 04:24:58 +0000 Subject: [PATCH] When we hit a #include directive that maps to a module import, emit a token representing the module import rather than making the module immediately visible. This serves two goals: * It avoids making declarations in the module visible prematurely, if we walk past the #include during a tentative parse, for instance, and * It gives a diagnostic (although, admittedly, not a very nice one) if a header with a corresponding module is included anywhere other than at the top level. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@194782 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/TokenKinds.def | 3 +++ include/clang/Sema/Sema.h | 4 ++++ lib/Frontend/PrintPreprocessedOutput.cpp | 5 +++++ lib/Lex/PPDirectives.cpp | 23 ++++++++++++++++++----- lib/Parse/Parser.cpp | 19 +++++++++++++++---- lib/Sema/SemaDecl.cpp | 6 ++++++ test/Modules/auto-module-import.m | 4 ++++ 7 files changed, 55 insertions(+), 9 deletions(-) diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def index c17449c4bd..6812cce2db 100644 --- a/include/clang/Basic/TokenKinds.def +++ b/include/clang/Basic/TokenKinds.def @@ -667,6 +667,9 @@ ANNOTATION(pragma_opencl_extension) ANNOTATION(pragma_openmp) ANNOTATION(pragma_openmp_end) +// Annotation for module import translated from #include etc. +ANNOTATION(module_include) + #undef ANNOTATION #undef TESTING_KEYWORD #undef OBJC2_AT_KEYWORD diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 19cef42436..ed285832c6 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -1600,6 +1600,10 @@ public: DeclResult ActOnModuleImport(SourceLocation AtLoc, SourceLocation ImportLoc, ModuleIdPath Path); + /// \brief The parser has processed a module import translated from a + /// #include or similar preprocessing directive. + void ActOnModuleInclude(SourceLocation DirectiveLoc, Module *Mod); + /// \brief Create an implicit import of the given module at the given /// source location. /// diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp index 3545d70744..55a66d87f8 100644 --- a/lib/Frontend/PrintPreprocessedOutput.cpp +++ b/lib/Frontend/PrintPreprocessedOutput.cpp @@ -657,6 +657,11 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok, // -traditional-cpp the lexer keeps /all/ whitespace, including comments. SourceLocation StartLoc = Tok.getLocation(); Callbacks->MoveToLine(StartLoc.getLocWithOffset(Tok.getLength())); + } else if (Tok.is(tok::annot_module_include)) { + // PrintPPOutputPPCallbacks::InclusionDirective handles producing + // appropriate output here. Ignore this token entirely. + PP.Lex(Tok); + continue; } else if (IdentifierInfo *II = Tok.getIdentifierInfo()) { OS << II->getName(); } else if (Tok.isLiteral() && !Tok.needsCleaning() && diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp index 9ba65a57a8..86c508fe9b 100644 --- a/lib/Lex/PPDirectives.cpp +++ b/lib/Lex/PPDirectives.cpp @@ -1603,10 +1603,9 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc, "@import " + PathString.str().str() + ";"); } - // Load the module. - // If this was an #__include_macros directive, only make macros visible. - Module::NameVisibilityKind Visibility - = (IncludeKind == 3)? Module::MacrosVisible : Module::AllVisible; + // Load the module. Only make macros visible. We'll make the declarations + // visible when the parser gets here. + Module::NameVisibilityKind Visibility = Module::MacrosVisible; ModuleLoadResult Imported = TheModuleLoader.loadModule(IncludeTok.getLocation(), Path, Visibility, /*IsIncludeDirective=*/true); @@ -1626,7 +1625,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc, } return; } - + // If this header isn't part of the module we're building, we're done. if (!BuildingImportedModule && Imported) { if (Callbacks) { @@ -1634,6 +1633,20 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc, FilenameRange, File, SearchPath, RelativePath, Imported); } + + if (IncludeKind != 3) { + // Let the parser know that we hit a module import, and it should + // make the module visible. + // FIXME: Produce this as the current token directly, rather than + // allocating a new token for it. + Token *Tok = new Token[1]; + Tok[0].startToken(); + Tok[0].setKind(tok::annot_module_include); + Tok[0].setLocation(HashLoc); + Tok[0].setAnnotationEndLoc(End); + Tok[0].setAnnotationValue(Imported); + EnterTokenStream(Tok, 1, true, true); + } return; } diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 84aad4101f..c6eac18aa4 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -566,19 +566,30 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) { if (PP.isIncrementalProcessingEnabled() && Tok.is(tok::eof)) ConsumeToken(); - while (Tok.is(tok::annot_pragma_unused)) + Result = DeclGroupPtrTy(); + switch (Tok.getKind()) { + case tok::annot_pragma_unused: HandlePragmaUnused(); + return false; - Result = DeclGroupPtrTy(); - if (Tok.is(tok::eof)) { + case tok::annot_module_include: + Actions.ActOnModuleInclude(Tok.getLocation(), + reinterpret_cast( + Tok.getAnnotationValue())); + ConsumeToken(); + return false; + + case tok::eof: // Late template parsing can begin. if (getLangOpts().DelayedTemplateParsing) Actions.SetLateTemplateParser(LateTemplateParserCallback, this); if (!PP.isIncrementalProcessingEnabled()) Actions.ActOnEndOfTranslationUnit(); //else don't tell Sema that we ended parsing: more input might come. - return true; + + default: + break; } ParsedAttributesWithRange attrs(AttrFactory); diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 211e8587d1..f5507791e7 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -12913,6 +12913,12 @@ DeclResult Sema::ActOnModuleImport(SourceLocation AtLoc, return Import; } +void Sema::ActOnModuleInclude(SourceLocation DirectiveLoc, Module *Mod) { + // FIXME: Should we synthesize an ImportDecl here? + PP.getModuleLoader().makeModuleVisible(Mod, Module::AllVisible, DirectiveLoc, + /*Complain=*/true); +} + void Sema::createImplicitModuleImport(SourceLocation Loc, Module *Mod) { // Create the implicit import declaration. TranslationUnitDecl *TU = getASTContext().getTranslationUnitDecl(); diff --git a/test/Modules/auto-module-import.m b/test/Modules/auto-module-import.m index 23bb63b924..d7fb9d1f9f 100644 --- a/test/Modules/auto-module-import.m +++ b/test/Modules/auto-module-import.m @@ -82,3 +82,7 @@ int getNoUmbrellaBPrivateFail() { return no_umbrella_B_private; } // expected-er int getNotInModule() { return not_in_module; } + +void includeNotAtTopLevel() { + #include // expected-warning {{treating #include as an import}} expected-error {{expected expression}} +} -- 2.40.0