]> granicus.if.org Git - clang/commitdiff
When we hit a #include directive that maps to a module import, emit a token
authorRichard Smith <richard-llvm@metafoo.co.uk>
Fri, 15 Nov 2013 04:24:58 +0000 (04:24 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Fri, 15 Nov 2013 04:24:58 +0000 (04:24 +0000)
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
include/clang/Sema/Sema.h
lib/Frontend/PrintPreprocessedOutput.cpp
lib/Lex/PPDirectives.cpp
lib/Parse/Parser.cpp
lib/Sema/SemaDecl.cpp
test/Modules/auto-module-import.m

index c17449c4bd428eaf819552bffc870d72ae9aae64..6812cce2dbeac10f2d6c0d2851d5066a691d142b 100644 (file)
@@ -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
index 19cef42436f7fa2df04f2576da65e074497261d6..ed285832c6bbd08909e06b7d4b0a482de973518f 100644 (file)
@@ -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.
   ///
index 3545d70744f05b6c3d2fb542d0c35e1dafade469..55a66d87f8bf5f04fd0f163d96a4ce563d6dca4e 100644 (file)
@@ -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() &&
index 9ba65a57a842fa3355a2969c4e753945dfdb9c48..86c508fe9b1b203af21b166982bc89702fd506f2 100644 (file)
@@ -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;
     }
 
index 84aad4101fbb4962dc9c12a6fb5691a81ba28874..c6eac18aa49c2a7bae5e9ceffc781eeadbfcba9a 100644 (file)
@@ -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<Module *>(
+                                   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);
index 211e8587d16d0c9e294d17d2e20244b9f207cd22..f5507791e7f610c27eb41b56cd9c901673bfa270 100644 (file)
@@ -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();
index 23bb63b924e1ecac8e9dd834ad5db06f8aa4afdd..d7fb9d1f9fd6fd8558ce2a6adcd6dcc887449613 100644 (file)
@@ -82,3 +82,7 @@ int getNoUmbrellaBPrivateFail() { return no_umbrella_B_private; } // expected-er
 int getNotInModule() {
   return not_in_module;
 }
+
+void includeNotAtTopLevel() {
+  #include <NoUmbrella/A.h> // expected-warning {{treating #include as an import}} expected-error {{expected expression}}
+}