diff options
| author | Qiongsi Wu <qiongsiwu@gmail.com> | 2025-08-22 09:18:01 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-08-22 09:18:01 -0700 |
| commit | 538e9e8ebd09233b3900ed2dfd23e4e1ca5c9fc0 (patch) | |
| tree | 5bd97ca3ccbbdf3c5f331ed8e29fed5c43a9229c /clang/lib/Lex/ModuleMapFile.cpp | |
| parent | c98413267cad77246d68f9434cbd279e200f1613 (diff) | |
[clang][Modules] Reporting Errors for Duplicating Link Declarations in `modulemap`s (#148959)
This PR teaches the modulemap parsing logic to report warnings that
default to 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.
The warning can be disabled with `-Wno-module-link-redeclaration`.
rdar://155880064
Diffstat (limited to 'clang/lib/Lex/ModuleMapFile.cpp')
| -rw-r--r-- | clang/lib/Lex/ModuleMapFile.cpp | 34 |
1 files changed, 30 insertions, 4 deletions
diff --git a/clang/lib/Lex/ModuleMapFile.cpp b/clang/lib/Lex/ModuleMapFile.cpp index 183e919d14c2..f0cd9d2bee82 100644 --- a/clang/lib/Lex/ModuleMapFile.cpp +++ b/clang/lib/Lex/ModuleMapFile.cpp @@ -118,7 +118,8 @@ struct ModuleMapFileParser { std::optional<ExcludeDecl> parseExcludeDecl(clang::SourceLocation LeadingLoc); std::optional<UmbrellaDirDecl> parseUmbrellaDirDecl(SourceLocation UmbrellaLoc); - std::optional<LinkDecl> parseLinkDecl(); + std::optional<LinkDecl> + parseLinkDecl(llvm::StringMap<SourceLocation> &SeenLinkDecl, bool Allowed); SourceLocation consumeToken(); void skipUntil(MMToken::TokenKind K); @@ -325,6 +326,7 @@ std::optional<ModuleDecl> ModuleMapFileParser::parseModuleDecl(bool TopLevel) { SourceLocation LBraceLoc = consumeToken(); bool Done = false; + llvm::StringMap<SourceLocation> SeenLinkDecl; do { std::optional<Decl> SubDecl; switch (Tok.Kind) { @@ -405,7 +407,9 @@ std::optional<ModuleDecl> ModuleMapFileParser::parseModuleDecl(bool TopLevel) { break; case MMToken::LinkKeyword: - SubDecl = parseLinkDecl(); + // Link decls are only allowed in top level modules or explicit + // submodules. + SubDecl = parseLinkDecl(SeenLinkDecl, TopLevel || MDecl.Explicit); break; default: @@ -822,7 +826,8 @@ ModuleMapFileParser::parseUmbrellaDirDecl(clang::SourceLocation UmbrellaLoc) { /// /// module-declaration: /// 'link' 'framework'[opt] string-literal -std::optional<LinkDecl> ModuleMapFileParser::parseLinkDecl() { +std::optional<LinkDecl> ModuleMapFileParser::parseLinkDecl( + llvm::StringMap<SourceLocation> &SeenLinkDecl, bool Allowed) { assert(Tok.is(MMToken::LinkKeyword)); LinkDecl LD; LD.Location = consumeToken(); @@ -838,12 +843,33 @@ std::optional<LinkDecl> ModuleMapFileParser::parseLinkDecl() { if (!Tok.is(MMToken::StringLiteral)) { Diags.Report(Tok.getLocation(), diag::err_mmap_expected_library_name) << LD.Framework << SourceRange(LD.Location); + consumeToken(); HadError = true; return std::nullopt; } - LD.Library = Tok.getString(); + StringRef Library = Tok.getString(); + + LD.Library = Library; consumeToken(); + + // Make sure we eat all the tokens when we report the errors so parsing + // can continue. + if (!Allowed) { + Diags.Report(LD.Location, diag::err_mmap_submodule_link_decl); + HadError = true; + return std::nullopt; + } + + auto [It, Inserted] = + SeenLinkDecl.insert(std::make_pair(Library, LD.Location)); + if (!Inserted) { + Diags.Report(LD.Location, diag::warn_mmap_link_redeclaration) << Library; + Diags.Report(It->second, diag::note_mmap_prev_link_declaration); + HadError = true; + return std::nullopt; + } + return std::move(LD); } |
