-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[clang][modules] Name the module map files on PCM file conflict #134475
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
Conversation
@llvm/pr-subscribers-clang Author: Jan Svoboda (jansvoboda11) ChangesWith implicitly-built modules, seeing something like:
is super confusing and not actionable, because the module cache tends to be hidden from the developer. This PR adds a note to that diagnostic that names the module map files the PCM files were compiled from, hopefully giving a good enough hint for further investigation:
(I had to replace the mechanism used to convert Full diff: https://github.com/llvm/llvm-project/pull/134475.diff 3 Files Affected:
diff --git a/clang/include/clang/Basic/DiagnosticSerializationKinds.td b/clang/include/clang/Basic/DiagnosticSerializationKinds.td
index 3914d3930bec7..5fc5937b80d35 100644
--- a/clang/include/clang/Basic/DiagnosticSerializationKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSerializationKinds.td
@@ -75,8 +75,7 @@ def err_module_file_not_module : Error<
def err_module_file_missing_top_level_submodule : Error<
"module file '%0' is missing its top-level submodule">, DefaultFatal;
def note_module_file_conflict : Note<
- "this is generally caused by modules with the same name found in multiple "
- "paths">;
+ "compiled from '%0' and '%1'">;
def remark_module_import : Remark<
"importing module '%0'%select{| into '%3'}2 from '%1'">,
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index d8d77e7f55232..6ee51122ea180 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -44,7 +44,6 @@
#include "clang/Basic/ASTSourceDescriptor.h"
#include "clang/Basic/CommentOptions.h"
#include "clang/Basic/Diagnostic.h"
-#include "clang/Basic/DiagnosticError.h"
#include "clang/Basic/DiagnosticIDs.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/DiagnosticSema.h"
@@ -1552,30 +1551,27 @@ void ASTReader::Error(unsigned DiagID, StringRef Arg1, StringRef Arg2,
Diag(DiagID) << Arg1 << Arg2 << Arg3;
}
+namespace {
+struct AlreadyReportedDiagnosticError
+ : llvm::ErrorInfo<AlreadyReportedDiagnosticError> {
+ static char ID;
+
+ void log(raw_ostream &OS) const override {
+ llvm_unreachable("reporting an already-reported diagnostic error");
+ }
+
+ std::error_code convertToErrorCode() const override {
+ return llvm::inconvertibleErrorCode();
+ }
+};
+
+char AlreadyReportedDiagnosticError::ID = 0;
+} // namespace
+
void ASTReader::Error(llvm::Error &&Err) const {
- llvm::Error RemainingErr =
- handleErrors(std::move(Err), [this](const DiagnosticError &E) {
- auto Diag = E.getDiagnostic().second;
-
- // Ideally we'd just emit it, but have to handle a possible in-flight
- // diagnostic. Note that the location is currently ignored as well.
- auto NumArgs = Diag.getStorage()->NumDiagArgs;
- assert(NumArgs <= 3 && "Can only have up to 3 arguments");
- StringRef Arg1, Arg2, Arg3;
- switch (NumArgs) {
- case 3:
- Arg3 = Diag.getStringArg(2);
- [[fallthrough]];
- case 2:
- Arg2 = Diag.getStringArg(1);
- [[fallthrough]];
- case 1:
- Arg1 = Diag.getStringArg(0);
- }
- Error(Diag.getDiagID(), Arg1, Arg2, Arg3);
- });
- if (RemainingErr)
- Error(toString(std::move(RemainingErr)));
+ handleAllErrors(
+ std::move(Err), [](AlreadyReportedDiagnosticError &) {},
+ [&](llvm::ErrorInfoBase &E) { return Error(E.message()); });
}
//===----------------------------------------------------------------------===//
@@ -3328,8 +3324,6 @@ ASTReader::ReadControlBlock(ModuleFile &F,
if (isDiagnosedResult(Result, Capabilities) || recompilingFinalized)
Diag(diag::note_module_file_imported_by)
<< F.FileName << !F.ModuleName.empty() << F.ModuleName;
- if (recompilingFinalized)
- Diag(diag::note_module_file_conflict);
switch (Result) {
case Failure: return Failure;
@@ -4419,6 +4413,7 @@ ASTReader::ReadModuleMapFileBlock(RecordData &Record, ModuleFile &F,
// This module was defined by an imported (explicit) module.
Diag(diag::err_module_file_conflict) << F.ModuleName << F.FileName
<< ASTFE->getName();
+ // TODO: Add a note with the module map paths if they differ.
} else {
// This module was built with a different module map.
Diag(diag::err_imported_module_not_found)
@@ -6067,14 +6062,21 @@ llvm::Error ASTReader::ReadSubmoduleBlock(ModuleFile &F,
if (OptionalFileEntryRef CurFile = CurrentModule->getASTFile()) {
// Don't emit module relocation error if we have -fno-validate-pch
if (!bool(PP.getPreprocessorOpts().DisablePCHOrModuleValidation &
- DisableValidationForModuleKind::Module) &&
- CurFile != F.File) {
- auto ConflictError =
- PartialDiagnostic(diag::err_module_file_conflict,
- ContextObj->DiagAllocator)
+ DisableValidationForModuleKind::Module)) {
+ assert(CurFile != F.File && "ModuleManager did not de-duplicate");
+
+ Diag(diag::err_module_file_conflict)
<< CurrentModule->getTopLevelModuleName() << CurFile->getName()
<< F.File.getName();
- return DiagnosticError::create(CurrentImportLoc, ConflictError);
+
+ auto CurModMapFile =
+ ModMap.getContainingModuleMapFile(CurrentModule);
+ auto ModMapFile = FileMgr.getOptionalFileRef(F.ModuleMapPath);
+ if (CurModMapFile && ModMapFile && CurModMapFile != ModMapFile)
+ Diag(diag::note_module_file_conflict)
+ << CurModMapFile->getName() << ModMapFile->getName();
+
+ return llvm::make_error<AlreadyReportedDiagnosticError>();
}
}
diff --git a/clang/test/ClangScanDeps/modules-relocated-mm-macro.c b/clang/test/ClangScanDeps/modules-relocated-mm-macro.c
index 17f479d9e0046..87fbad0c72131 100644
--- a/clang/test/ClangScanDeps/modules-relocated-mm-macro.c
+++ b/clang/test/ClangScanDeps/modules-relocated-mm-macro.c
@@ -13,13 +13,14 @@
// RUN: cp -r %t/frameworks2/A.framework %t/frameworks1
-// RUN: not clang-scan-deps -format experimental-full -o %t/deps2.json -- \
+// RUN: not clang-scan-deps -format experimental-full -o %t/deps2.json 2>%t/errs -- \
// RUN: %clang -fmodules -fmodules-cache-path=%t/cache \
// RUN: -F %t/frameworks1 -F %t/frameworks2 \
-// RUN: -c %t/tu2.m -o %t/tu2.o \
-// RUN: 2>&1 | FileCheck %s
+// RUN: -c %t/tu2.m -o %t/tu2.o
+// RUN: FileCheck --input-file=%t/errs %s
-// CHECK: fatal error: module 'A' is defined in both '{{.*}}.pcm' and '{{.*}}.pcm'
+// CHECK: fatal error: module 'A' is defined in both '{{.*}}.pcm' and '{{.*}}.pcm'
+// CHECK-NEXT: note: compiled from '{{.*}}frameworks1{{.*}}' and '{{.*}}frameworks2{{.*}}'
//--- frameworks2/A.framework/Modules/module.modulemap
framework module A { header "A.h" }
|
@llvm/pr-subscribers-clang-modules Author: Jan Svoboda (jansvoboda11) ChangesWith implicitly-built modules, seeing something like:
is super confusing and not actionable, because the module cache tends to be hidden from the developer. This PR adds a note to that diagnostic that names the module map files the PCM files were compiled from, hopefully giving a good enough hint for further investigation:
(I had to replace the mechanism used to convert Full diff: https://github.com/llvm/llvm-project/pull/134475.diff 3 Files Affected:
diff --git a/clang/include/clang/Basic/DiagnosticSerializationKinds.td b/clang/include/clang/Basic/DiagnosticSerializationKinds.td
index 3914d3930bec7..5fc5937b80d35 100644
--- a/clang/include/clang/Basic/DiagnosticSerializationKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSerializationKinds.td
@@ -75,8 +75,7 @@ def err_module_file_not_module : Error<
def err_module_file_missing_top_level_submodule : Error<
"module file '%0' is missing its top-level submodule">, DefaultFatal;
def note_module_file_conflict : Note<
- "this is generally caused by modules with the same name found in multiple "
- "paths">;
+ "compiled from '%0' and '%1'">;
def remark_module_import : Remark<
"importing module '%0'%select{| into '%3'}2 from '%1'">,
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index d8d77e7f55232..6ee51122ea180 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -44,7 +44,6 @@
#include "clang/Basic/ASTSourceDescriptor.h"
#include "clang/Basic/CommentOptions.h"
#include "clang/Basic/Diagnostic.h"
-#include "clang/Basic/DiagnosticError.h"
#include "clang/Basic/DiagnosticIDs.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/DiagnosticSema.h"
@@ -1552,30 +1551,27 @@ void ASTReader::Error(unsigned DiagID, StringRef Arg1, StringRef Arg2,
Diag(DiagID) << Arg1 << Arg2 << Arg3;
}
+namespace {
+struct AlreadyReportedDiagnosticError
+ : llvm::ErrorInfo<AlreadyReportedDiagnosticError> {
+ static char ID;
+
+ void log(raw_ostream &OS) const override {
+ llvm_unreachable("reporting an already-reported diagnostic error");
+ }
+
+ std::error_code convertToErrorCode() const override {
+ return llvm::inconvertibleErrorCode();
+ }
+};
+
+char AlreadyReportedDiagnosticError::ID = 0;
+} // namespace
+
void ASTReader::Error(llvm::Error &&Err) const {
- llvm::Error RemainingErr =
- handleErrors(std::move(Err), [this](const DiagnosticError &E) {
- auto Diag = E.getDiagnostic().second;
-
- // Ideally we'd just emit it, but have to handle a possible in-flight
- // diagnostic. Note that the location is currently ignored as well.
- auto NumArgs = Diag.getStorage()->NumDiagArgs;
- assert(NumArgs <= 3 && "Can only have up to 3 arguments");
- StringRef Arg1, Arg2, Arg3;
- switch (NumArgs) {
- case 3:
- Arg3 = Diag.getStringArg(2);
- [[fallthrough]];
- case 2:
- Arg2 = Diag.getStringArg(1);
- [[fallthrough]];
- case 1:
- Arg1 = Diag.getStringArg(0);
- }
- Error(Diag.getDiagID(), Arg1, Arg2, Arg3);
- });
- if (RemainingErr)
- Error(toString(std::move(RemainingErr)));
+ handleAllErrors(
+ std::move(Err), [](AlreadyReportedDiagnosticError &) {},
+ [&](llvm::ErrorInfoBase &E) { return Error(E.message()); });
}
//===----------------------------------------------------------------------===//
@@ -3328,8 +3324,6 @@ ASTReader::ReadControlBlock(ModuleFile &F,
if (isDiagnosedResult(Result, Capabilities) || recompilingFinalized)
Diag(diag::note_module_file_imported_by)
<< F.FileName << !F.ModuleName.empty() << F.ModuleName;
- if (recompilingFinalized)
- Diag(diag::note_module_file_conflict);
switch (Result) {
case Failure: return Failure;
@@ -4419,6 +4413,7 @@ ASTReader::ReadModuleMapFileBlock(RecordData &Record, ModuleFile &F,
// This module was defined by an imported (explicit) module.
Diag(diag::err_module_file_conflict) << F.ModuleName << F.FileName
<< ASTFE->getName();
+ // TODO: Add a note with the module map paths if they differ.
} else {
// This module was built with a different module map.
Diag(diag::err_imported_module_not_found)
@@ -6067,14 +6062,21 @@ llvm::Error ASTReader::ReadSubmoduleBlock(ModuleFile &F,
if (OptionalFileEntryRef CurFile = CurrentModule->getASTFile()) {
// Don't emit module relocation error if we have -fno-validate-pch
if (!bool(PP.getPreprocessorOpts().DisablePCHOrModuleValidation &
- DisableValidationForModuleKind::Module) &&
- CurFile != F.File) {
- auto ConflictError =
- PartialDiagnostic(diag::err_module_file_conflict,
- ContextObj->DiagAllocator)
+ DisableValidationForModuleKind::Module)) {
+ assert(CurFile != F.File && "ModuleManager did not de-duplicate");
+
+ Diag(diag::err_module_file_conflict)
<< CurrentModule->getTopLevelModuleName() << CurFile->getName()
<< F.File.getName();
- return DiagnosticError::create(CurrentImportLoc, ConflictError);
+
+ auto CurModMapFile =
+ ModMap.getContainingModuleMapFile(CurrentModule);
+ auto ModMapFile = FileMgr.getOptionalFileRef(F.ModuleMapPath);
+ if (CurModMapFile && ModMapFile && CurModMapFile != ModMapFile)
+ Diag(diag::note_module_file_conflict)
+ << CurModMapFile->getName() << ModMapFile->getName();
+
+ return llvm::make_error<AlreadyReportedDiagnosticError>();
}
}
diff --git a/clang/test/ClangScanDeps/modules-relocated-mm-macro.c b/clang/test/ClangScanDeps/modules-relocated-mm-macro.c
index 17f479d9e0046..87fbad0c72131 100644
--- a/clang/test/ClangScanDeps/modules-relocated-mm-macro.c
+++ b/clang/test/ClangScanDeps/modules-relocated-mm-macro.c
@@ -13,13 +13,14 @@
// RUN: cp -r %t/frameworks2/A.framework %t/frameworks1
-// RUN: not clang-scan-deps -format experimental-full -o %t/deps2.json -- \
+// RUN: not clang-scan-deps -format experimental-full -o %t/deps2.json 2>%t/errs -- \
// RUN: %clang -fmodules -fmodules-cache-path=%t/cache \
// RUN: -F %t/frameworks1 -F %t/frameworks2 \
-// RUN: -c %t/tu2.m -o %t/tu2.o \
-// RUN: 2>&1 | FileCheck %s
+// RUN: -c %t/tu2.m -o %t/tu2.o
+// RUN: FileCheck --input-file=%t/errs %s
-// CHECK: fatal error: module 'A' is defined in both '{{.*}}.pcm' and '{{.*}}.pcm'
+// CHECK: fatal error: module 'A' is defined in both '{{.*}}.pcm' and '{{.*}}.pcm'
+// CHECK-NEXT: note: compiled from '{{.*}}frameworks1{{.*}}' and '{{.*}}frameworks2{{.*}}'
//--- frameworks2/A.framework/Modules/module.modulemap
framework module A { header "A.h" }
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, a minor non-blocking question. Thank you!
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/190/builds/18138 Here is the relevant piece of the build log for the reference
|
…#134475) With implicitly-built modules, seeing something like: ``` fatal error: module 'X' is defined in both '<cache>/HASH1/X-HASH2.pcm' and '<cache>/HASH1/X-HASH3.pcm' ``` is super confusing and not actionable, because the module cache tends to be hidden from the developer. This PR adds a note to that diagnostic that names the module map files the PCM files were compiled from, hopefully giving a good enough hint for further investigation: ``` note: compiled from '<build>/X.framework/Modules/module.modulemap' and '<SDK>/X.framework/Modules/module.modulemap' ``` (I had to replace the mechanism used to convert `DiagnosticError` into something `DiagnosticsEngine` can understand, because it seemingly did not support notes.)
With implicitly-built modules, seeing something like:
is super confusing and not actionable, because the module cache tends to be hidden from the developer.
This PR adds a note to that diagnostic that names the module map files the PCM files were compiled from, hopefully giving a good enough hint for further investigation:
(I had to replace the mechanism used to convert
DiagnosticError
into somethingDiagnosticsEngine
can understand, because it seemingly did not support notes.)