[clang] [clang][Modules] Reporting Errors for Duplicating Link Declarations in `modulemap`s (PR #148959)

Qiongsi Wu via cfe-commits cfe-commits at lists.llvm.org
Tue Jul 15 13:54:35 PDT 2025


https://github.com/qiongsiwu created https://github.com/llvm/llvm-project/pull/148959

This PR teaches the modulemap parsing logic to report errors if the parsing logic sees duplicating link declarations in the same module. Specifically, duplicating link declarations means multiple link declarations with the same string-literal in the same module. No errors are reported if a same link declaration exist in a submodule and its enclosing module. 

>From 0e8a0db8ace8fd1f450cf2364b4c975d418eddc1 Mon Sep 17 00:00:00 2001
From: Qiongsi Wu <qiongsi_wu at apple.com>
Date: Mon, 14 Jul 2025 18:22:27 -0700
Subject: [PATCH] Initial implementation of modulemap link decl duplication
 check.

---
 .../include/clang/Basic/DiagnosticLexKinds.td |  2 ++
 clang/lib/Lex/ModuleMap.cpp                   | 12 ++++++++
 .../ClangScanDeps/link-libraries-diag-dup.c   | 30 +++++++++++++++++++
 3 files changed, 44 insertions(+)
 create mode 100644 clang/test/ClangScanDeps/link-libraries-diag-dup.c

diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td
index 723f5d48b4f5f..f3c9e63a7ca61 100644
--- a/clang/include/clang/Basic/DiagnosticLexKinds.td
+++ b/clang/include/clang/Basic/DiagnosticLexKinds.td
@@ -909,6 +909,8 @@ def err_mmap_nested_submodule_id : Error<
   "qualified module name can only be used to define modules at the top level">;
 def err_mmap_expected_feature : Error<"expected a feature name">;
 def err_mmap_expected_attribute : Error<"expected an attribute name">;
+def err_mmap_link_redecalration : Error<"redeclaration of link library '%0'">;
+def note_mmap_prev_link_declaration : Note<"previously declared here">;
 def warn_mmap_unknown_attribute : Warning<"unknown attribute '%0'">,
   InGroup<IgnoredAttributes>;
 def warn_mmap_mismatched_private_submodule : Warning<
diff --git a/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp
index 637a08fe4dcdb..5f815f38a4f54 100644
--- a/clang/lib/Lex/ModuleMap.cpp
+++ b/clang/lib/Lex/ModuleMap.cpp
@@ -1570,6 +1570,10 @@ class ModuleMapLoader {
   /// 'textual' to match the original intent.
   llvm::SmallPtrSet<Module *, 2> UsesRequiresExcludedHack;
 
+  /// Tracks the link library decls in the module map.
+  llvm::DenseMap<Module *, llvm::StringMap<SourceLocation>>
+      LinkLibraryLibStrMap;
+
   void handleModuleDecl(const modulemap::ModuleDecl &MD);
   void handleExternModuleDecl(const modulemap::ExternModuleDecl &EMD);
   void handleRequiresDecl(const modulemap::RequiresDecl &RD);
@@ -2067,6 +2071,14 @@ void ModuleMapLoader::handleUseDecl(const modulemap::UseDecl &UD) {
 }
 
 void ModuleMapLoader::handleLinkDecl(const modulemap::LinkDecl &LD) {
+  auto &LibStrMap = LinkLibraryLibStrMap[ActiveModule];
+  auto [It, Inserted] =
+      LibStrMap.insert(std::make_pair(LD.Library, LD.Location));
+  if (!Inserted) {
+    Diags.Report(LD.Location, diag::err_mmap_link_redecalration) << LD.Library;
+    Diags.Report(It->second, diag::note_mmap_prev_link_declaration);
+    return;
+  }
   ActiveModule->LinkLibraries.push_back(
       Module::LinkLibrary(std::string{LD.Library}, LD.Framework));
 }
diff --git a/clang/test/ClangScanDeps/link-libraries-diag-dup.c b/clang/test/ClangScanDeps/link-libraries-diag-dup.c
new file mode 100644
index 0000000000000..c04769465fe0b
--- /dev/null
+++ b/clang/test/ClangScanDeps/link-libraries-diag-dup.c
@@ -0,0 +1,30 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: split-file %s %t
+
+//--- module.modulemap
+module A {
+  umbrella header "A.h"
+
+  link "libraryA"
+  link "libraryA"
+}
+
+//--- A.h
+// empty
+//--- TU.c
+#include "A.h"
+
+//--- cdb.json.template
+[{
+  "file": "DIR/TU.c",
+  "directory": "DIR",
+  "command": "clang -fmodules -fmodules-cache-path=DIR/cache -I DIR -c DIR/TU.c"
+}]
+
+// RUN: sed "s|DIR|%/t|g" %t/cdb.json.template > %t/cdb.json
+// RUN: not clang-scan-deps -compilation-database %t/cdb.json -format \
+// RUN:   experimental-full 2>&1 | FileCheck %s
+
+// CHECK:      module.modulemap:5:3: error: redeclaration of link library 'libraryA'
+// CHECK-NEXT: module.modulemap:4:3: note: previously declared here



More information about the cfe-commits mailing list