[prev in list] [next in list] [prev in thread] [next in thread] 

List:       cfe-commits
Subject:    [PATCH] D11403: [Modules] Add Darwin-specific compatibility module map parsing hacks
From:       Ben Langmuir <blangmuir () apple ! com>
Date:       2015-07-22 3:21:09
Message-ID: differential-rev-PHID-DREV-qndxqswltcsjmjs63pmq-req () reviews ! llvm ! org
[Download RAW message or body]

benlangmuir created this revision.
benlangmuir added reviewers: rsmith, silvas.
benlangmuir added a subscriber: cfe-commits.
benlangmuir set the repository for this revision to rL LLVM.

I ended up restricting the "requires excluded" hack to the specifically named modules \
after all.  It turned out to only affect the two modules I had found: \
Darwin.C.excluded and Tcl.Private.  I tested this back to OS X 10.8 and iOS 7.

   This preserves backwards compatibility for two hacks in the Darwin
    system module map files:
    
    1. The use of 'requires excluded' to make headers non-modular, which
    should really be mapped to 'textual' now that we have this feature.
    
    2. Silently removes a bogus cplusplus requirement from IOKit.avc.
    
    Once we start diagnosing missing requirements and headers on
    auto-imports these would have broken compatibility with existing Darwin
    SDKs.

Repository:
  rL LLVM

http://reviews.llvm.org/D11403

Files:
  include/clang/Basic/Module.h
  lib/Basic/Module.cpp
  lib/Lex/ModuleMap.cpp
  test/Modules/Inputs/System/usr/include/assert.h
  test/Modules/Inputs/System/usr/include/module.map
  test/Modules/Inputs/System/usr/include/tcl-private/header.h
  test/Modules/darwin_specific_modulemap_hacks.m


["D11403.30312.patch" (text/x-patch)]

Index: test/Modules/darwin_specific_modulemap_hacks.m
===================================================================
--- /dev/null
+++ test/Modules/darwin_specific_modulemap_hacks.m
@@ -0,0 +1,22 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fimplicit-module-maps -isystem \
%S/Inputs/System/usr/include -triple x86_64-apple-darwin10 %s -verify -fsyntax-only \
+// expected-no-diagnostics +
+@import Darwin.C.excluded; // no error, header is implicitly 'textual'
+@import Tcl.Private;       // no error, header is implicitly 'textual'
+@import IOKit.avc;         // no error, cplusplus requirement removed
+
+#if defined(DARWIN_C_EXCLUDED)
+#error assert.h should be textual
+#elif defined(TCL_PRIVATE)
+#error tcl-private/header.h should be textual
+#endif
+
+#import <assert.h>
+#import <tcl-private/header.h>
+
+#if !defined(DARWIN_C_EXCLUDED)
+#error assert.h missing
+#elif !defined(TCL_PRIVATE)
+#error tcl-private/header.h missing
+#endif
Index: test/Modules/Inputs/System/usr/include/tcl-private/header.h
===================================================================
--- /dev/null
+++ test/Modules/Inputs/System/usr/include/tcl-private/header.h
@@ -0,0 +1,2 @@
+// tcl-private/header.h
+#define TCL_PRIVATE 1
Index: test/Modules/Inputs/System/usr/include/module.map
===================================================================
--- test/Modules/Inputs/System/usr/include/module.map
+++ test/Modules/Inputs/System/usr/include/module.map
@@ -30,3 +30,25 @@
   header "uses_other_constants.h"
   export *
 }
+
+module Darwin {
+  module C {
+    module excluded {
+      requires excluded
+      header "assert.h"
+    }
+  }
+}
+
+module Tcl {
+  module Private {
+    requires excluded
+    umbrella ""
+  }
+}
+
+module IOKit {
+  module avc {
+    requires cplusplus
+  }
+}
Index: test/Modules/Inputs/System/usr/include/assert.h
===================================================================
--- /dev/null
+++ test/Modules/Inputs/System/usr/include/assert.h
@@ -0,0 +1,2 @@
+// assert.h
+#define DARWIN_C_EXCLUDED 1
Index: lib/Lex/ModuleMap.cpp
===================================================================
--- lib/Lex/ModuleMap.cpp
+++ lib/Lex/ModuleMap.cpp
@@ -1570,6 +1570,26 @@
             : File->getDir(), ExternLoc);
 }
 
+static bool shouldAddRequirement(Module *M, StringRef Feature,
+                                 bool &IsRequiresExcludedHack) {
+  if (Feature == "excluded" || Feature == "cplusplus") {
+    std::string FullName = M->getFullModuleName();
+    if (FullName == "Darwin.C.excluded" || FullName == "Tcl.Private") {
+      // We will mark the module contents non-modular. See doc comment for
+      // Module::UsesRequiresExcludedHack.
+      IsRequiresExcludedHack = true;
+      return false;
+    } else if (FullName == "IOKit.avc") {
+      // This module was mistakenly marked 'requires cplusplus' in older Darwin
+      // SDK versions. As a backwards compatibility hack, don't add the
+      // requirement.
+      return false;
+    }
+  }
+
+  return true;
+}
+
 /// \brief Parse a requires declaration.
 ///
 ///   requires-declaration:
@@ -1605,9 +1625,16 @@
     std::string Feature = Tok.getString();
     consumeToken();
 
-    // Add this feature.
-    ActiveModule->addRequirement(Feature, RequiredState,
-                                 Map.LangOpts, *Map.Target);
+    bool IsRequiresExcludedHack = false;
+    bool ShouldAddRequirement =
+        shouldAddRequirement(ActiveModule, Feature, IsRequiresExcludedHack);
+    ActiveModule->UsesRequiresExcludedHack |= IsRequiresExcludedHack;
+
+    if (ShouldAddRequirement) {
+      // Add this feature.
+      ActiveModule->addRequirement(Feature, RequiredState, Map.LangOpts,
+                                   *Map.Target);
+    }
 
     if (!Tok.is(MMToken::Comma))
       break;
@@ -1657,9 +1684,16 @@
       consumeToken();
     }
   }
+
   if (LeadingToken == MMToken::TextualKeyword)
     Role = ModuleMap::ModuleHeaderRole(Role | ModuleMap::TextualHeader);
 
+  if (ActiveModule->UsesRequiresExcludedHack) {
+    // Mark this header 'textual' (see doc comment for
+    // Module::UsesRequiresExcludedHack).
+    Role = ModuleMap::ModuleHeaderRole(Role | ModuleMap::TextualHeader);
+  }
+
   if (LeadingToken != MMToken::HeaderKeyword) {
     if (!Tok.is(MMToken::HeaderKeyword)) {
       Diags.Report(Tok.getLocation(), diag::err_mmap_expected_header)
@@ -1838,14 +1872,33 @@
     HadError = true;
     return;
   }
-  
+
+  if (ActiveModule->UsesRequiresExcludedHack) {
+    // Mark this header 'textual' (see doc comment for
+    // Module::UsesRequiresExcludedHack). Although iterating over the directory
+    // is relatively expensive, in practice this only applies to the uncommonly
+    // used Tcl module on Darwin platforms.
+    std::error_code EC;
+    for (llvm::sys::fs::recursive_directory_iterator I(Dir->getName(), EC), E;
+         I != E && !EC; I.increment(EC)) {
+      if (const FileEntry *FE = SourceMgr.getFileManager().getFile(I->path())) {
+        // FIXME: Taking the name from the FileEntry is unstable and can give
+        // different results depending on how we've previously named that file
+        // in this build.
+        Module::Header Header = {FE->getName(), FE};
+        Map.addHeader(ActiveModule, Header, ModuleMap::TextualHeader);
+      }
+    }
+    return;
+  }
+
   if (Module *OwningModule = Map.UmbrellaDirs[Dir]) {
     Diags.Report(UmbrellaLoc, diag::err_mmap_umbrella_clash)
       << OwningModule->getFullModuleName();
     HadError = true;
     return;
-  } 
-  
+  }
+
   // Record this umbrella directory.
   Map.setUmbrellaDir(ActiveModule, Dir, DirName);
 }
Index: lib/Basic/Module.cpp
===================================================================
--- lib/Basic/Module.cpp
+++ lib/Basic/Module.cpp
@@ -32,7 +32,8 @@
       IsFramework(IsFramework), IsExplicit(IsExplicit), IsSystem(false),
       IsExternC(false), IsInferred(false), InferSubmodules(false),
       InferExplicitSubmodules(false), InferExportWildcard(false),
-      ConfigMacrosExhaustive(false), NameVisibility(Hidden) {
+      ConfigMacrosExhaustive(false), UsesRequiresExcludedHack(false),
+      NameVisibility(Hidden) {
   if (Parent) {
     if (!Parent->isAvailable())
       IsAvailable = false;
Index: include/clang/Basic/Module.h
===================================================================
--- include/clang/Basic/Module.h
+++ include/clang/Basic/Module.h
@@ -200,6 +200,16 @@
   /// built.
   unsigned ConfigMacrosExhaustive : 1;
 
+  /// \brief Whether this module uses the 'requires excluded' hack to mark its
+  /// contents as 'textual'.
+  ///
+  /// On older Darwin SDK versions, 'requires excluded' is used to mark the
+  /// contents of the Darwin.C.excluded (assert.h) and Tcl.Private modules as
+  /// non-modular headers.  For backwards compatibility, we continue to support
+  /// this idiom for just these modules, and map the headers to 'textual' to
+  /// match the original intent.
+  unsigned UsesRequiresExcludedHack : 1;
+
   /// \brief Describes the visibility of the various names within a
   /// particular module.
   enum NameVisibilityKind {



_______________________________________________
cfe-commits mailing list
cfe-commits@cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic