r305758 - Support non-identifier module names when preprocessing modules.

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Mon Jun 19 16:09:37 PDT 2017


Author: rsmith
Date: Mon Jun 19 18:09:36 2017
New Revision: 305758

URL: http://llvm.org/viewvc/llvm-project?rev=305758&view=rev
Log:
Support non-identifier module names when preprocessing modules.

Modified:
    cfe/trunk/include/clang/Basic/Module.h
    cfe/trunk/lib/Basic/Module.cpp
    cfe/trunk/lib/Frontend/CompilerInstance.cpp
    cfe/trunk/lib/Frontend/PrintPreprocessedOutput.cpp
    cfe/trunk/lib/Frontend/Rewrite/FrontendActions.cpp
    cfe/trunk/lib/Frontend/Rewrite/InclusionRewriter.cpp
    cfe/trunk/lib/Lex/Pragma.cpp
    cfe/trunk/test/Modules/string_names.cpp

Modified: cfe/trunk/include/clang/Basic/Module.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Module.h?rev=305758&r1=305757&r2=305758&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Module.h (original)
+++ cfe/trunk/include/clang/Basic/Module.h Mon Jun 19 18:09:36 2017
@@ -393,7 +393,9 @@ public:
 
   /// \brief Retrieve the full name of this module, including the path from
   /// its top-level module.
-  std::string getFullModuleName() const;
+  /// \param AllowStringLiterals If \c true, components that might not be
+  ///        lexically valid as identifiers will be emitted as string literals.
+  std::string getFullModuleName(bool AllowStringLiterals = false) const;
 
   /// \brief Whether the full name of this module is equal to joining
   /// \p nameParts with "."s.

Modified: cfe/trunk/lib/Basic/Module.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/Module.cpp?rev=305758&r1=305757&r2=305758&view=diff
==============================================================================
--- cfe/trunk/lib/Basic/Module.cpp (original)
+++ cfe/trunk/lib/Basic/Module.cpp Mon Jun 19 18:09:36 2017
@@ -13,6 +13,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "clang/Basic/Module.h"
+#include "clang/Basic/CharInfo.h"
 #include "clang/Basic/FileManager.h"
 #include "clang/Basic/LangOptions.h"
 #include "clang/Basic/TargetInfo.h"
@@ -125,7 +126,36 @@ const Module *Module::getTopLevelModule(
   return Result;
 }
 
-std::string Module::getFullModuleName() const {
+static StringRef getModuleNameFromComponent(
+    const std::pair<std::string, SourceLocation> &IdComponent) {
+  return IdComponent.first;
+}
+static StringRef getModuleNameFromComponent(StringRef R) { return R; }
+
+template<typename InputIter>
+static void printModuleId(raw_ostream &OS, InputIter Begin, InputIter End,
+                          bool AllowStringLiterals = true) {
+  for (InputIter It = Begin; It != End; ++It) {
+    if (It != Begin)
+      OS << ".";
+
+    StringRef Name = getModuleNameFromComponent(*It);
+    if (!AllowStringLiterals || isValidIdentifier(Name))
+      OS << Name;
+    else {
+      OS << '"';
+      OS.write_escaped(Name);
+      OS << '"';
+    }
+  }
+}
+
+template<typename Container>
+static void printModuleId(raw_ostream &OS, const Container &C) {
+  return printModuleId(OS, C.begin(), C.end());
+}
+
+std::string Module::getFullModuleName(bool AllowStringLiterals) const {
   SmallVector<StringRef, 2> Names;
   
   // Build up the set of module names (from innermost to outermost).
@@ -133,15 +163,11 @@ std::string Module::getFullModuleName()
     Names.push_back(M->Name);
   
   std::string Result;
-  for (SmallVectorImpl<StringRef>::reverse_iterator I = Names.rbegin(),
-                                                 IEnd = Names.rend();
-       I != IEnd; ++I) {
-    if (!Result.empty())
-      Result += '.';
-    
-    Result += *I;
-  }
-  
+
+  llvm::raw_string_ostream Out(Result);
+  printModuleId(Out, Names.rbegin(), Names.rend(), AllowStringLiterals);
+  Out.flush(); 
+
   return Result;
 }
 
@@ -240,14 +266,6 @@ Module *Module::findSubmodule(StringRef
   return SubModules[Pos->getValue()];
 }
 
-static void printModuleId(raw_ostream &OS, const ModuleId &Id) {
-  for (unsigned I = 0, N = Id.size(); I != N; ++I) {
-    if (I)
-      OS << ".";
-    OS << Id[I].first;
-  }
-}
-
 void Module::getExportedModules(SmallVectorImpl<Module *> &Exported) const {
   // All non-explicit submodules are exported.
   for (std::vector<Module *>::const_iterator I = SubModules.begin(),
@@ -334,7 +352,8 @@ void Module::print(raw_ostream &OS, unsi
     OS << "framework ";
   if (IsExplicit)
     OS << "explicit ";
-  OS << "module " << Name;
+  OS << "module ";
+  printModuleId(OS, &Name, &Name + 1);
 
   if (IsSystem || IsExternC) {
     OS.indent(Indent + 2);
@@ -434,7 +453,7 @@ void Module::print(raw_ostream &OS, unsi
     OS.indent(Indent + 2);
     OS << "export ";
     if (Module *Restriction = Exports[I].getPointer()) {
-      OS << Restriction->getFullModuleName();
+      OS << Restriction->getFullModuleName(true);
       if (Exports[I].getInt())
         OS << ".*";
     } else {
@@ -455,7 +474,7 @@ void Module::print(raw_ostream &OS, unsi
   for (unsigned I = 0, N = DirectUses.size(); I != N; ++I) {
     OS.indent(Indent + 2);
     OS << "use ";
-    OS << DirectUses[I]->getFullModuleName();
+    OS << DirectUses[I]->getFullModuleName(true);
     OS << "\n";
   }
 
@@ -488,7 +507,7 @@ void Module::print(raw_ostream &OS, unsi
   for (unsigned I = 0, N = Conflicts.size(); I != N; ++I) {
     OS.indent(Indent + 2);
     OS << "conflict ";
-    OS << Conflicts[I].Other->getFullModuleName();
+    OS << Conflicts[I].Other->getFullModuleName(true);
     OS << ", \"";
     OS.write_escaped(Conflicts[I].Message);
     OS << "\"\n";

Modified: cfe/trunk/lib/Frontend/CompilerInstance.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CompilerInstance.cpp?rev=305758&r1=305757&r2=305758&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/CompilerInstance.cpp (original)
+++ cfe/trunk/lib/Frontend/CompilerInstance.cpp Mon Jun 19 18:09:36 2017
@@ -11,6 +11,7 @@
 #include "clang/AST/ASTConsumer.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/Decl.h"
+#include "clang/Basic/CharInfo.h"
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/FileManager.h"
 #include "clang/Basic/MemoryBufferCache.h"
@@ -1902,17 +1903,23 @@ CompilerInstance::loadModule(SourceLocat
 void CompilerInstance::loadModuleFromSource(SourceLocation ImportLoc,
                                             StringRef ModuleName,
                                             StringRef Source) {
+  // Avoid creating filenames with special characters.
+  SmallString<128> CleanModuleName(ModuleName);
+  for (auto &C : CleanModuleName)
+    if (!isAlphanumeric(C))
+      C = '_';
+
   // FIXME: Using a randomized filename here means that our intermediate .pcm
   // output is nondeterministic (as .pcm files refer to each other by name).
   // Can this affect the output in any way?
   SmallString<128> ModuleFileName;
   if (std::error_code EC = llvm::sys::fs::createTemporaryFile(
-          ModuleName, "pcm", ModuleFileName)) {
+          CleanModuleName, "pcm", ModuleFileName)) {
     getDiagnostics().Report(ImportLoc, diag::err_fe_unable_to_open_output)
         << ModuleFileName << EC.message();
     return;
   }
-  std::string ModuleMapFileName = (ModuleName + ".map").str();
+  std::string ModuleMapFileName = (CleanModuleName + ".map").str();
 
   FrontendInputFile Input(
       ModuleMapFileName,

Modified: cfe/trunk/lib/Frontend/PrintPreprocessedOutput.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/PrintPreprocessedOutput.cpp?rev=305758&r1=305757&r2=305758&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/PrintPreprocessedOutput.cpp (original)
+++ cfe/trunk/lib/Frontend/PrintPreprocessedOutput.cpp Mon Jun 19 18:09:36 2017
@@ -349,7 +349,7 @@ void PrintPPOutputPPCallbacks::Inclusion
     case tok::pp_include_next:
       startNewLineIfNeeded();
       MoveToLine(HashLoc);
-      OS << "#pragma clang module import " << Imported->getFullModuleName()
+      OS << "#pragma clang module import " << Imported->getFullModuleName(true)
          << " /* clang -E: implicit import for "
          << "#" << PP.getSpelling(IncludeTok) << " "
          << (IsAngled ? '<' : '"') << FileName << (IsAngled ? '>' : '"')
@@ -378,14 +378,14 @@ void PrintPPOutputPPCallbacks::Inclusion
 /// Handle entering the scope of a module during a module compilation.
 void PrintPPOutputPPCallbacks::BeginModule(const Module *M) {
   startNewLineIfNeeded();
-  OS << "#pragma clang module begin " << M->getFullModuleName();
+  OS << "#pragma clang module begin " << M->getFullModuleName(true);
   setEmittedDirectiveOnThisLine();
 }
 
 /// Handle leaving the scope of a module during a module compilation.
 void PrintPPOutputPPCallbacks::EndModule(const Module *M) {
   startNewLineIfNeeded();
-  OS << "#pragma clang module end /*" << M->getFullModuleName() << "*/";
+  OS << "#pragma clang module end /*" << M->getFullModuleName(true) << "*/";
   setEmittedDirectiveOnThisLine();
 }
 

Modified: cfe/trunk/lib/Frontend/Rewrite/FrontendActions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/Rewrite/FrontendActions.cpp?rev=305758&r1=305757&r2=305758&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/Rewrite/FrontendActions.cpp (original)
+++ cfe/trunk/lib/Frontend/Rewrite/FrontendActions.cpp Mon Jun 19 18:09:36 2017
@@ -9,6 +9,7 @@
 
 #include "clang/Rewrite/Frontend/FrontendActions.h"
 #include "clang/AST/ASTConsumer.h"
+#include "clang/Basic/CharInfo.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/FrontendActions.h"
 #include "clang/Frontend/FrontendDiagnostic.h"
@@ -224,7 +225,15 @@ public:
     auto OS = Out.lock();
     assert(OS && "loaded module file after finishing rewrite action?");
 
-    (*OS) << "#pragma clang module build " << MF->ModuleName << "\n";
+    (*OS) << "#pragma clang module build ";
+    if (isValidIdentifier(MF->ModuleName))
+      (*OS) << MF->ModuleName;
+    else {
+      (*OS) << '"';
+      OS->write_escaped(MF->ModuleName);
+      (*OS) << '"';
+    }
+    (*OS) << '\n';
 
     // Rewrite the contents of the module in a separate compiler instance.
     CompilerInstance Instance(CI.getPCHContainerOperations(),

Modified: cfe/trunk/lib/Frontend/Rewrite/InclusionRewriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/Rewrite/InclusionRewriter.cpp?rev=305758&r1=305757&r2=305758&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/Rewrite/InclusionRewriter.cpp (original)
+++ cfe/trunk/lib/Frontend/Rewrite/InclusionRewriter.cpp Mon Jun 19 18:09:36 2017
@@ -140,7 +140,7 @@ void InclusionRewriter::WriteLineInfo(St
 }
 
 void InclusionRewriter::WriteImplicitModuleImport(const Module *Mod) {
-  OS << "#pragma clang module import " << Mod->getFullModuleName()
+  OS << "#pragma clang module import " << Mod->getFullModuleName(true)
      << " /* clang -frewrite-includes: implicit import */" << MainEOL;
 }
 
@@ -471,15 +471,15 @@ void InclusionRewriter::Process(FileID F
             else if (const IncludedFile *Inc = FindIncludeAtLocation(Loc)) {
               const Module *Mod = FindEnteredModule(Loc);
               if (Mod)
-                OS << "#pragma clang module begin " << Mod->getFullModuleName()
-                   << "\n";
+                OS << "#pragma clang module begin "
+                   << Mod->getFullModuleName(true) << "\n";
 
               // Include and recursively process the file.
               Process(Inc->Id, Inc->FileType);
 
               if (Mod)
-                OS << "#pragma clang module end /*" << Mod->getFullModuleName()
-                   << "*/\n";
+                OS << "#pragma clang module end /*"
+                   << Mod->getFullModuleName(true) << "*/\n";
 
               // Add line marker to indicate we're returning from an included
               // file.

Modified: cfe/trunk/lib/Lex/Pragma.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/Pragma.cpp?rev=305758&r1=305757&r2=305758&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/Pragma.cpp (original)
+++ cfe/trunk/lib/Lex/Pragma.cpp Mon Jun 19 18:09:36 2017
@@ -20,6 +20,7 @@
 #include "clang/Basic/TokenKinds.h"
 #include "clang/Lex/HeaderSearch.h"
 #include "clang/Lex/LexDiagnostic.h"
+#include "clang/Lex/LiteralSupport.h"
 #include "clang/Lex/MacroInfo.h"
 #include "clang/Lex/PPCallbacks.h"
 #include "clang/Lex/Preprocessor.h"
@@ -754,15 +755,52 @@ void Preprocessor::HandlePragmaIncludeAl
   getHeaderSearchInfo().AddIncludeAlias(OriginalSource, ReplaceFileName);
 }
 
+// Lex a component of a module name: either an identifier or a string literal;
+// for components that can be expressed both ways, the two forms are equivalent.
+static bool LexModuleNameComponent(
+    Preprocessor &PP, Token &Tok,
+    std::pair<IdentifierInfo *, SourceLocation> &ModuleNameComponent,
+    bool First) {
+  PP.LexUnexpandedToken(Tok);
+  if (Tok.is(tok::string_literal) && !Tok.hasUDSuffix()) {
+    StringLiteralParser Literal(Tok, PP);
+    if (Literal.hadError)
+      return true;
+    ModuleNameComponent = std::make_pair(
+        PP.getIdentifierInfo(Literal.GetString()), Tok.getLocation());
+  } else if (!Tok.isAnnotation() && Tok.getIdentifierInfo()) {
+    ModuleNameComponent =
+        std::make_pair(Tok.getIdentifierInfo(), Tok.getLocation());
+  } else {
+    PP.Diag(Tok.getLocation(), diag::err_pp_expected_module_name) << First;
+    return true;
+  }
+  return false;
+}
+
+static bool LexModuleName(
+    Preprocessor &PP, Token &Tok,
+    llvm::SmallVectorImpl<std::pair<IdentifierInfo *, SourceLocation>>
+        &ModuleName) {
+  while (true) {
+    std::pair<IdentifierInfo*, SourceLocation> NameComponent;
+    if (LexModuleNameComponent(PP, Tok, NameComponent, ModuleName.empty()))
+      return true;
+    ModuleName.push_back(NameComponent);
+
+    PP.LexUnexpandedToken(Tok);
+    if (Tok.isNot(tok::period))
+      return false;
+  }
+}
+
 void Preprocessor::HandlePragmaModuleBuild(Token &Tok) {
   SourceLocation Loc = Tok.getLocation();
 
-  LexUnexpandedToken(Tok);
-  if (Tok.isAnnotation() || !Tok.getIdentifierInfo()) {
-    Diag(Tok.getLocation(), diag::err_pp_expected_module_name) << true;
+  std::pair<IdentifierInfo *, SourceLocation> ModuleNameLoc;
+  if (LexModuleNameComponent(*this, Tok, ModuleNameLoc, true))
     return;
-  }
-  IdentifierInfo *ModuleName = Tok.getIdentifierInfo();
+  IdentifierInfo *ModuleName = ModuleNameLoc.first;
 
   LexUnexpandedToken(Tok);
   if (Tok.isNot(tok::eod)) {
@@ -1383,26 +1421,6 @@ public:
   }
 };
 
-static bool LexModuleName(
-    Preprocessor &PP, Token &Tok,
-    llvm::SmallVectorImpl<std::pair<IdentifierInfo *, SourceLocation>>
-        &ModuleName) {
-  while (true) {
-    PP.LexUnexpandedToken(Tok);
-    if (Tok.isAnnotation() || !Tok.getIdentifierInfo()) {
-      PP.Diag(Tok.getLocation(), diag::err_pp_expected_module_name)
-        << ModuleName.empty();
-      return true;
-    }
-
-    ModuleName.emplace_back(Tok.getIdentifierInfo(), Tok.getLocation());
-
-    PP.LexUnexpandedToken(Tok);
-    if (Tok.isNot(tok::period))
-      return false;
-  }
-}
-
 /// Handle the clang \#pragma module import extension. The syntax is:
 /// \code
 ///   #pragma clang module import some.module.name
@@ -1473,7 +1491,7 @@ struct PragmaModuleBeginHandler : public
     // be loaded or implicitly loadable.
     // FIXME: We could create the submodule here. We'd need to know whether
     // it's supposed to be explicit, but not much else.
-    Module *M = PP.getHeaderSearchInfo().getModuleMap().findModule(Current);
+    Module *M = PP.getHeaderSearchInfo().lookupModule(Current);
     if (!M) {
       PP.Diag(ModuleName.front().second,
               diag::err_pp_module_begin_no_module_map) << Current;

Modified: cfe/trunk/test/Modules/string_names.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/string_names.cpp?rev=305758&r1=305757&r2=305758&view=diff
==============================================================================
--- cfe/trunk/test/Modules/string_names.cpp (original)
+++ cfe/trunk/test/Modules/string_names.cpp Mon Jun 19 18:09:36 2017
@@ -1,6 +1,10 @@
 // RUN: rm -rf %t
 // RUN: %clang_cc1 -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -fmodules-decluse -I %S/Inputs/string_names %s -fmodule-name="my/module-a" -verify
 
+// Check that we can preprocess with string module names.
+// RUN: %clang_cc1 -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -I %S/Inputs/string_names %s -fmodule-name="my/module-a" -E -frewrite-imports -o %t/test.ii
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-decluse -I %S/Inputs/string_names %t/test.ii -fmodule-name="my/module-a"
+
 #include "a.h"
 #include "b.h" // expected-error {{does not depend on a module exporting}}
 #include "c.h"




More information about the cfe-commits mailing list