Skip to content

[clang][modules] Don't prevent translation of FW_Private includes when explicitly building FW #70714

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 1, 2023

Conversation

jansvoboda11
Copy link
Contributor

We prevent translating #include <FW/PrivateHeader.h> into an import of FW_Private when compiling the implementation of FW or FW_Private. This is specified via -fmodule-name= on the TU command line (used to be -fmodule-implementation-of).

This logic is supposed to only kick in when imported directly from a TU, but it currently also kicks in when compiling the public FW module explicitly (since it also has -fmodule-name= on the command line).

This patch makes sure this logic only kicks in for the case that used to be -fmodule-implementation-of (for the TU), and not for all -fmodule-name= cases (especially for the explicit compile of a module).

rdar://101051277; related: rdar://37500098&38434694

…n explicitly building FW

We prevent translating `#include <FW/PrivateHeader.h>` into an import of FW_Private when compiling the implementation of FW or FW_Private. This is specified via `-fmodule-name=` on the TU command line (used to be `-fmodule-implementation-of`).

This logic is supposed to only kick in when imported directly from a TU, but it currently also kicks in when compiling the public FW module explicitly (since it also has `-fmodule-name=` on the command line).

This patch makes sure this logic only kicks in for the case that used to be `-fmodule-implementation-of` (for the TU), and not for all `-fmodule-name=` cases (especially for the explicit compile of a module).

rdar://101051277; related: rdar://37500098&38434694
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:modules C++20 modules and Clang Header Modules labels Oct 30, 2023
@llvmbot
Copy link
Member

llvmbot commented Oct 30, 2023

@llvm/pr-subscribers-clang

@llvm/pr-subscribers-clang-modules

Author: Jan Svoboda (jansvoboda11)

Changes

We prevent translating #include &lt;FW/PrivateHeader.h&gt; into an import of FW_Private when compiling the implementation of FW or FW_Private. This is specified via -fmodule-name= on the TU command line (used to be -fmodule-implementation-of).

This logic is supposed to only kick in when imported directly from a TU, but it currently also kicks in when compiling the public FW module explicitly (since it also has -fmodule-name= on the command line).

This patch makes sure this logic only kicks in for the case that used to be -fmodule-implementation-of (for the TU), and not for all -fmodule-name= cases (especially for the explicit compile of a module).

rdar://101051277; related: rdar://37500098&38434694


Full diff: https://github.com/llvm/llvm-project/pull/70714.diff

2 Files Affected:

  • (modified) clang/lib/Basic/Module.cpp (+4-3)
  • (added) clang/test/ClangScanDeps/modules-priv-fw-from-pub.m (+121)
diff --git a/clang/lib/Basic/Module.cpp b/clang/lib/Basic/Module.cpp
index cc2e5be98d32d34..e4ac1abf12a7f8e 100644
--- a/clang/lib/Basic/Module.cpp
+++ b/clang/lib/Basic/Module.cpp
@@ -161,9 +161,10 @@ bool Module::isForBuilding(const LangOptions &LangOpts) const {
   StringRef TopLevelName = getTopLevelModuleName();
   StringRef CurrentModule = LangOpts.CurrentModule;
 
-  // When building framework Foo, we want to make sure that Foo *and*
-  // Foo_Private are textually included and no modules are built for both.
-  if (getTopLevelModule()->IsFramework &&
+  // When building the implementation of framework Foo, we want to make sure
+  // that Foo *and* Foo_Private are textually included and no modules are built
+  // for either.
+  if (!LangOpts.isCompilingModule() && getTopLevelModule()->IsFramework &&
       CurrentModule == LangOpts.ModuleName &&
       !CurrentModule.endswith("_Private") && TopLevelName.endswith("_Private"))
     TopLevelName = TopLevelName.drop_back(8);
diff --git a/clang/test/ClangScanDeps/modules-priv-fw-from-pub.m b/clang/test/ClangScanDeps/modules-priv-fw-from-pub.m
new file mode 100644
index 000000000000000..cb82e0c366322c9
--- /dev/null
+++ b/clang/test/ClangScanDeps/modules-priv-fw-from-pub.m
@@ -0,0 +1,121 @@
+// This test checks that importing private headers from the public headers of
+// a framework is consistent between the dependency scanner and the explicit build.
+
+// RUN: rm -rf %t
+// RUN: split-file %s %t
+
+//--- frameworks/FW.framework/Modules/module.modulemap
+framework module FW { header "FW.h" }
+//--- frameworks/FW.framework/Modules/module.private.modulemap
+framework module FW_Private { header "FW_Private.h"}
+//--- frameworks/FW.framework/Headers/FW.h
+#include <FW/FW_Private.h>
+//--- frameworks/FW.framework/PrivateHeaders/FW_Private.h
+@import Dependency;
+
+//--- modules/module.modulemap
+module Dependency { header "dependency.h" }
+//--- modules/dependency.h
+// empty
+
+//--- tu.m
+#include <FW/FW.h>
+
+//--- cdb.json.in
+[{
+  "file": "DIR/tu.m",
+  "directory": "DIR",
+  "command": "clang -fmodules -fmodules-cache-path=DIR/cache -fimplicit-module-maps -I DIR/modules -F DIR/frameworks -Wno-framework-include-private-from-public -Wno-atimport-in-framework-header -c DIR/tu.m -o DIR/tu.o"
+}]
+
+// RUN: sed -e "s|DIR|%/t|g" %t/cdb.json.in > %t/cdb.json
+// RUN: clang-scan-deps -compilation-database %t/cdb.json -format experimental-full > %t/deps.json
+
+// Check that FW is reported to depend on FW_Private.
+// RUN: cat %t/deps.json | sed 's:\\\\\?:/:g' | FileCheck %s -DPREFIX=%/t
+// CHECK:      {
+// CHECK-NEXT:   "modules": [
+// CHECK-NEXT:     {
+// CHECK-NEXT:       "clang-module-deps": [],
+// CHECK-NEXT:       "clang-modulemap-file": "[[PREFIX]]/modules/module.modulemap",
+// CHECK-NEXT:       "command-line": [
+// CHECK:            ],
+// CHECK-NEXT:       "context-hash": "{{.*}}",
+// CHECK-NEXT:       "file-deps": [
+// CHECK-NEXT:         "[[PREFIX]]/modules/dependency.h",
+// CHECK-NEXT:         "[[PREFIX]]/modules/module.modulemap"
+// CHECK-NEXT:       ],
+// CHECK-NEXT:       "name": "Dependency"
+// CHECK-NEXT:     },
+// CHECK-NEXT:     {
+// CHECK-NEXT:       "clang-module-deps": [
+// CHECK-NEXT:         {
+// CHECK-NEXT:           "context-hash": "{{.*}}",
+// CHECK-NEXT:           "module-name": "FW_Private"
+// CHECK-NEXT:         }
+// CHECK-NEXT:       ],
+// CHECK-NEXT:       "clang-modulemap-file": "[[PREFIX]]/frameworks/FW.framework/Modules/module.modulemap",
+// CHECK-NEXT:       "command-line": [
+// CHECK:            ],
+// CHECK-NEXT:       "context-hash": "{{.*}}",
+// CHECK-NEXT:       "file-deps": [
+// CHECK-NEXT:         "[[PREFIX]]/frameworks/FW.framework/Headers/FW.h",
+// CHECK-NEXT:         "[[PREFIX]]/frameworks/FW.framework/Modules/module.modulemap",
+// CHECK-NEXT:         "[[PREFIX]]/frameworks/FW.framework/Modules/module.private.modulemap"
+// CHECK-NEXT:       ],
+// CHECK-NEXT:       "name": "FW"
+// CHECK-NEXT:     },
+// CHECK-NEXT:     {
+// CHECK-NEXT:       "clang-module-deps": [
+// CHECK-NEXT:         {
+// CHECK-NEXT:           "context-hash": "{{.*}}",
+// CHECK-NEXT:           "module-name": "Dependency"
+// CHECK-NEXT:         }
+// CHECK-NEXT:       ],
+// CHECK-NEXT:       "clang-modulemap-file": "[[PREFIX]]/frameworks/FW.framework/Modules/module.private.modulemap",
+// CHECK-NEXT:       "command-line": [
+// CHECK:            ],
+// CHECK-NEXT:       "context-hash": "{{.*}}",
+// CHECK-NEXT:       "file-deps": [
+// CHECK-NEXT:         "[[PREFIX]]/frameworks/FW.framework/Modules/module.private.modulemap",
+// CHECK-NEXT:         "[[PREFIX]]/frameworks/FW.framework/PrivateHeaders/FW_Private.h",
+// CHECK-NEXT:         "[[PREFIX]]/modules/module.modulemap"
+// CHECK-NEXT:       ],
+// CHECK-NEXT:       "name": "FW_Private"
+// CHECK-NEXT:     }
+// CHECK-NEXT:   ],
+// CHECK-NEXT:   "translation-units": [
+// CHECK-NEXT:     {
+// CHECK-NEXT:       "commands": [
+// CHECK-NEXT:         {
+// CHECK-NEXT:           "clang-context-hash": "{{.*}}",
+// CHECK-NEXT:           "clang-module-deps": [
+// CHECK-NEXT:             {
+// CHECK-NEXT:               "context-hash": "{{.*}}",
+// CHECK-NEXT:               "module-name": "FW"
+// CHECK-NEXT:             }
+// CHECK-NEXT:           ],
+// CHECK-NEXT:           "command-line": [
+// CHECK:                ],
+// CHECK-NEXT:           "executable": "clang",
+// CHECK-NEXT:           "file-deps": [
+// CHECK-NEXT:             "[[PREFIX]]/tu.m"
+// CHECK-NEXT:           ],
+// CHECK-NEXT:           "input-file": "[[PREFIX]]/tu.m"
+// CHECK-NEXT:         }
+// CHECK-NEXT:       ]
+// CHECK-NEXT:     }
+// CHECK-NEXT:   ]
+// CHECK-NEXT: }
+
+// Check that building FW succeeds. If FW_Private was to be treated textually,
+// building FW would fail due to Dependency not being present on the command line.
+// RUN: %deps-to-rsp %t/deps.json --module-name=Dependency > %t/Dependency.cc1.rsp
+// RUN: %deps-to-rsp %t/deps.json --module-name=FW_Private > %t/FW_Private.cc1.rsp
+// RUN: %deps-to-rsp %t/deps.json --module-name=FW > %t/FW.cc1.rsp
+// RUN: %deps-to-rsp %t/deps.json --tu-index=0 > %t/tu.rsp
+
+// RUN: %clang @%t/Dependency.cc1.rsp
+// RUN: %clang @%t/FW_Private.cc1.rsp
+// RUN: %clang @%t/FW.cc1.rsp
+// RUN: %clang @%t/tu.rsp

@jansvoboda11 jansvoboda11 merged commit a3efd89 into llvm:main Nov 1, 2023
@jansvoboda11 jansvoboda11 deleted the priv-fw-from-pub branch November 1, 2023 19:00
jansvoboda11 added a commit to swiftlang/llvm-project that referenced this pull request Nov 1, 2023
…n explicitly building FW (llvm#70714)

We prevent translating `#include <FW/PrivateHeader.h>` into an import of
FW_Private when compiling the implementation of FW or FW_Private. This
is specified via `-fmodule-name=` on the TU command line (used to be
`-fmodule-implementation-of`).

This logic is supposed to only kick in when imported directly from a TU,
but it currently also kicks in when compiling the public FW module
explicitly (since it also has `-fmodule-name=` on the command line).

This patch makes sure this logic only kicks in for the case that used to
be `-fmodule-implementation-of` (for the TU), and not for all
`-fmodule-name=` cases (especially for the explicit compile of a
module).

rdar://101051277; related: rdar://37500098&38434694
(cherry picked from commit a3efd89)
jansvoboda11 added a commit to swiftlang/llvm-project that referenced this pull request Nov 2, 2023
…-pub

[clang][modules] Don't prevent translation of FW_Private includes when explicitly building FW (llvm#70714)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:modules C++20 modules and Clang Header Modules clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants