Repository: llvm/llvm-project
Pull request #141540: [NFCI] Change SpecialCaseList::inSectionBlame to return pair<uint, uint> (FileIdx, LineNo).
Author: login: qinkunbao
Labels: name: llvm:support
Created: 2025-05-27T02:36:31Z | Merged: 2025-05-28T04:18:37Z

Accoring to the discussion in https://github.com/llvm/llvm-project/pull/140529, we need to SSCL can be
created from multiple ignore list files, so we can repeat-fsanitize-ignorelist=. The change is necessary to achieve the feature described in https://github.com/llvm/llvm-project/issues/139128.



Diff:
diff --git a/llvm/include/llvm/Support/SpecialCaseList.h b/llvm/include/llvm/Support/SpecialCaseList.h
index 653a3b14ebf03..22a62eac9e01a 100644
--- a/llvm/include/llvm/Support/SpecialCaseList.h
+++ b/llvm/include/llvm/Support/SpecialCaseList.h
@@ -18,6 +18,7 @@
 #include "llvm/Support/Regex.h"
 #include <memory>
 #include <string>
+#include <utility>
 #include <vector>
 
 namespace llvm {
@@ -69,6 +70,7 @@ class FileSystem;
 /// ---
 class SpecialCaseList {
 public:
+  static constexpr std::pair<unsigned, unsigned> NotFound = {0, 0};
   /// Parses the special case list entries from files. On failure, returns
   /// 0 and writes an error message to string.
   LLVM_ABI static std::unique_ptr<SpecialCaseList>
@@ -93,17 +95,17 @@ class SpecialCaseList {
   LLVM_ABI bool inSection(StringRef Section, StringRef Prefix, StringRef Query,
                           StringRef Category = StringRef()) const;
 
-  /// Returns the line number corresponding to the special case list entry if
-  /// the special case list contains a line
+  /// Returns the file index and the line number <FileIdx, LineNo> corresponding
+  /// to the special case list entry if the special case list contains a line
   /// \code
   ///   @Prefix:<E>=@Category
   /// \endcode
   /// where @Query satisfies the glob <E> in a given @Section.
-  /// Returns zero if there is no exclusion entry corresponding to this
+  /// Returns (zero, zero) if there is no exclusion entry corresponding to this
   /// expression.
-  LLVM_ABI unsigned inSectionBlame(StringRef Section, StringRef Prefix,
-                                   StringRef Query,
-                                   StringRef Category = StringRef()) const;
+  LLVM_ABI std::pair<unsigned, unsigned>
+  inSectionBlame(StringRef Section, StringRef Prefix, StringRef Query,
+                 StringRef Category = StringRef()) const;
 
 protected:
   // Implementations of the create*() functions that can also be used by derived
@@ -142,21 +144,24 @@ class SpecialCaseList {
   using SectionEntries = StringMap<StringMap<Matcher>>;
 
   struct Section {
-    Section(std::unique_ptr<Matcher> M) : SectionMatcher(std::move(M)) {};
-    Section() : Section(std::make_unique<Matcher>()) {};
+    Section(StringRef Str, unsigned FileIdx)
+        : SectionStr(Str), FileIdx(FileIdx) {};
 
-    std::unique_ptr<Matcher> SectionMatcher;
+    std::unique_ptr<Matcher> SectionMatcher = std::make_unique<Matcher>();
     SectionEntries Entries;
     std::string SectionStr;
+    unsigned FileIdx;
   };
 
   std::vector<Section> Sections;
 
-  LLVM_ABI Expected<Section *> addSection(StringRef SectionStr, unsigned LineNo,
+  LLVM_ABI Expected<Section *> addSection(StringRef SectionStr,
+                                          unsigned FileIdx, unsigned LineNo,
                                           bool UseGlobs = true);
 
   /// Parses just-constructed SpecialCaseList entries from a memory buffer.
-  LLVM_ABI bool parse(const MemoryBuffer *MB, std::string &Error);
+  LLVM_ABI bool parse(unsigned FileIdx, const MemoryBuffer *MB,
+                      std::string &Error);
 
   // Helper method for derived classes to search by Prefix, Query, and Category
   // once they have already resolved a section entry.
diff --git a/llvm/lib/Support/SpecialCaseList.cpp b/llvm/lib/Support/SpecialCaseList.cpp
index f9b5aafe88e98..8d4e043bc1c9f 100644
--- a/llvm/lib/Support/SpecialCaseList.cpp
+++ b/llvm/lib/Support/SpecialCaseList.cpp
@@ -105,7 +105,8 @@ SpecialCaseList::createOrDie(const std::vector<std::string> &Paths,
 
 bool SpecialCaseList::createInternal(const std::vector<std::string> &Paths,
                                      vfs::FileSystem &VFS, std::string &Error) {
-  for (const auto &Path : Paths) {
+  for (size_t i = 0; i < Paths.size(); ++i) {
+    const auto &Path = Paths[i];
     ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr =
         VFS.getBufferForFile(Path);
     if (std::error_code EC = FileOrErr.getError()) {
@@ -113,7 +114,7 @@ bool SpecialCaseList::createInternal(const std::vector<std::string> &Paths,
       return false;
     }
     std::string ParseError;
-    if (!parse(FileOrErr.get().get(), ParseError)) {
+    if (!parse(i, FileOrErr.get().get(), ParseError)) {
       Error = (Twine("error parsing file '") + Path + "': " + ParseError).str();
       return false;
     }
@@ -123,17 +124,16 @@ bool SpecialCaseList::createInternal(const std::vector<std::string> &Paths,
 
 bool SpecialCaseList::createInternal(const MemoryBuffer *MB,
                                      std::string &Error) {
-  if (!parse(MB, Error))
+  if (!parse(0, MB, Error))
     return false;
   return true;
 }
 
 Expected<SpecialCaseList::Section *>
-SpecialCaseList::addSection(StringRef SectionStr, unsigned LineNo,
-                            bool UseGlobs) {
-  Sections.emplace_back();
+SpecialCaseList::addSection(StringRef SectionStr, unsigned FileNo,
+                            unsigned LineNo, bool UseGlobs) {
+  Sections.emplace_back(SectionStr, FileNo);
   auto &Section = Sections.back();
-  Section.SectionStr = SectionStr;
 
   if (auto Err = Section.SectionMatcher->insert(SectionStr, LineNo, UseGlobs)) {
     return createStringError(errc::invalid_argument,
@@ -145,9 +145,10 @@ SpecialCaseList::addSection(StringRef SectionStr, unsigned LineNo,
   return &Section;
 }
 
-bool SpecialCaseList::parse(const MemoryBuffer *MB, std::string &Error) {
+bool SpecialCaseList::parse(unsigned FileIdx, const MemoryBuffer *MB,
+                            std::string &Error) {
   Section *CurrentSection;
-  if (auto Err = addSection("*", 1).moveInto(CurrentSection)) {
+  if (auto Err = addSection("*", FileIdx, 1).moveInto(CurrentSection)) {
     Error = toString(std::move(Err));
     return false;
   }
@@ -175,7 +176,8 @@ bool SpecialCaseList::parse(const MemoryBuffer *MB, std::string &Error) {
         return false;
       }
 
-      if (auto Err = addSection(Line.drop_front().drop_back(), LineNo, UseGlobs)
+      if (auto Err = addSection(Line.drop_front().drop_back(), FileIdx, LineNo,
+                                UseGlobs)
                          .moveInto(CurrentSection)) {
         Error = toString(std::move(Err));
         return false;
@@ -208,20 +210,21 @@ SpecialCaseList::~SpecialCaseList() = default;
 
 bool SpecialCaseList::inSection(StringRef Section, StringRef Prefix,
                                 StringRef Query, StringRef Category) const {
-  return inSectionBlame(Section, Prefix, Query, Category);
+  auto [FileIdx, LineNo] = inSectionBlame(Section, Prefix, Query, Category);
+  return LineNo;
 }
 
-unsigned SpecialCaseList::inSectionBlame(StringRef Section, StringRef Prefix,
-                                         StringRef Query,
-                                         StringRef Category) const {
+std::pair<unsigned, unsigned>
+SpecialCaseList::inSectionBlame(StringRef Section, StringRef Prefix,
+                                StringRef Query, StringRef Category) const {
   for (const auto &S : reverse(Sections)) {
     if (S.SectionMatcher->match(Section)) {
       unsigned Blame = inSectionBlame(S.Entries, Prefix, Query, Category);
       if (Blame)
-        return Blame;
+        return {S.FileIdx, Blame};
     }
   }
-  return 0;
+  return NotFound;
 }
 
 unsigned SpecialCaseList::inSectionBlame(const SectionEntries &Entries,
diff --git a/llvm/tools/llvm-cfi-verify/llvm-cfi-verify.cpp b/llvm/tools/llvm-cfi-verify/llvm-cfi-verify.cpp
index 0f2c7da94230e..b372957204691 100644
--- a/llvm/tools/llvm-cfi-verify/llvm-cfi-verify.cpp
+++ b/llvm/tools/llvm-cfi-verify/llvm-cfi-verify.cpp
@@ -78,8 +78,7 @@ static void printBlameContext(const DILineInfo &LineInfo, unsigned Context) {
   File->getBuffer().split(Lines, '\n');
 
   for (unsigned i = std::max<size_t>(1, LineInfo.Line - Context);
-       i <
-       std::min<size_t>(Lines.size() + 1, LineInfo.Line + Context + 1);
+       i < std::min<size_t>(Lines.size() + 1, LineInfo.Line + Context + 1);
        ++i) {
     if (i == LineInfo.Line)
       outs() << ">";
@@ -193,12 +192,16 @@ printIndirectCFInstructions(FileAnalysis &Analysis,
 
     unsigned BlameLine = 0;
     for (auto &K : {"cfi-icall", "cfi-vcall"}) {
-      if (!BlameLine)
-        BlameLine =
+      if (!BlameLine) {
+        auto [FileIdx, Line] =
             SpecialCaseList->inSectionBlame(K, "src", LineInfo.FileName);
-      if (!BlameLine)
-        BlameLine =
+        BlameLine = Line;
+      }
+      if (!BlameLine) {
+        auto [FileIdx, Line] =
             SpecialCaseList->inSectionBlame(K, "fun", LineInfo.FunctionName);
+        BlameLine = Line;
+      }
     }
 
     if (BlameLine) {
diff --git a/llvm/unittests/Support/SpecialCaseListTest.cpp b/llvm/unittests/Support/SpecialCaseListTest.cpp
index 05bd0e63adc20..5be2b9e3a7a5d 100644
--- a/llvm/unittests/Support/SpecialCaseListTest.cpp
+++ b/llvm/unittests/Support/SpecialCaseListTest.cpp
@@ -14,6 +14,7 @@
 #include "gtest/gtest.h"
 
 using testing::HasSubstr;
+using testing::Pair;
 using testing::StartsWith;
 using namespace llvm;
 
@@ -70,13 +71,14 @@ TEST_F(SpecialCaseListTest, Basic) {
   EXPECT_FALSE(SCL->inSection("", "fun", "hello"));
   EXPECT_FALSE(SCL->inSection("", "src", "hello", "category"));
 
-  EXPECT_EQ(3u, SCL->inSectionBlame("", "src", "hello"));
-  EXPECT_EQ(4u, SCL->inSectionBlame("", "src", "bye"));
-  EXPECT_EQ(5u, SCL->inSectionBlame("", "src", "hi", "category"));
-  EXPECT_EQ(6u, SCL->inSectionBlame("", "src", "zzzz", "category"));
-  EXPECT_EQ(0u, SCL->inSectionBlame("", "src", "hi"));
-  EXPECT_EQ(0u, SCL->inSectionBlame("", "fun", "hello"));
-  EXPECT_EQ(0u, SCL->inSectionBlame("", "src", "hello", "category"));
+  EXPECT_THAT(SCL->inSectionBlame("", "src", "hello"), Pair(0u, 3u));
+  EXPECT_THAT(SCL->inSectionBlame("", "src", "bye"), Pair(0u, 4u));
+  EXPECT_THAT(SCL->inSectionBlame("", "src", "hi", "category"), Pair(0u, 5u));
+  EXPECT_THAT(SCL->inSectionBlame("", "src", "zzzz", "category"), Pair(0u, 6u));
+  EXPECT_THAT(SCL->inSectionBlame("", "src", "hi"), Pair(0u, 0u));
+  EXPECT_THAT(SCL->inSectionBlame("", "fun", "hello"), Pair(0u, 0u));
+  EXPECT_THAT(SCL->inSectionBlame("", "src", "hello", "category"),
+              Pair(0u, 0u));
 }
 
 TEST_F(SpecialCaseListTest, CorrectErrorLineNumberWithBlankLine) {
@@ -311,8 +313,8 @@ TEST_F(SpecialCaseListTest, LinesInSection) {
   std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("fun:foo\n"
                                                              "fun:bar\n"
                                                              "fun:foo\n");
-  EXPECT_EQ(3u, SCL->inSectionBlame("sect1", "fun", "foo"));
-  EXPECT_EQ(2u, SCL->inSectionBlame("sect1", "fun", "bar"));
+  EXPECT_THAT(SCL->inSectionBlame("sect1", "fun", "foo"), Pair(0u, 3u));
+  EXPECT_THAT(SCL->inSectionBlame("sect1", "fun", "bar"), Pair(0u, 2u));
 }
 
 TEST_F(SpecialCaseListTest, LinesCrossSection) {
@@ -321,8 +323,8 @@ TEST_F(SpecialCaseListTest, LinesCrossSection) {
                                                              "fun:foo\n"
                                                              "[sect1]\n"
                                                              "fun:bar\n");
-  EXPECT_EQ(3u, SCL->inSectionBlame("sect1", "fun", "foo"));
-  EXPECT_EQ(5u, SCL->inSectionBlame("sect1", "fun", "bar"));
+  EXPECT_THAT(SCL->inSectionBlame("sect1", "fun", "foo"), Pair(0u, 3u));
+  EXPECT_THAT(SCL->inSectionBlame("sect1", "fun", "bar"), Pair(0u, 5u));
 }
 
 TEST_F(SpecialCaseListTest, Blame) {
@@ -341,10 +343,33 @@ TEST_F(SpecialCaseListTest, Blame) {
   EXPECT_TRUE(SCL->inSection("sect2", "src", "def"));
   EXPECT_TRUE(SCL->inSection("sect1", "src", "def"));
 
-  EXPECT_EQ(2u, SCL->inSectionBlame("sect1", "src", "fooz"));
-  EXPECT_EQ(4u, SCL->inSectionBlame("sect1", "src", "barz"));
-  EXPECT_EQ(5u, SCL->inSectionBlame("sect1", "src", "def"));
-  EXPECT_EQ(8u, SCL->inSectionBlame("sect2", "src", "def"));
-  EXPECT_EQ(8u, SCL->inSectionBlame("sect2", "src", "dez"));
+  EXPECT_THAT(SCL->inSectionBlame("sect1", "src", "fooz"), Pair(0u, 2u));
+  EXPECT_THAT(SCL->inSectionBlame("sect1", "src", "barz"), Pair(0u, 4u));
+  EXPECT_THAT(SCL->inSectionBlame("sect1", "src", "def"), Pair(0u, 5u));
+  EXPECT_THAT(SCL->inSectionBlame("sect2", "src", "def"), Pair(0u, 8u));
+  EXPECT_THAT(SCL->inSectionBlame("sect2", "src", "dez"), Pair(0u, 8u));
 }
+
+TEST_F(SpecialCaseListTest, FileIdx) {
+  std::vector<std::string> Files;
+  Files.push_back(makeSpecialCaseListFile("src:bar\n"
+                                          "src:*foo*\n"
+                                          "src:ban=init\n"
+                                          "src:baz\n"
+                                          "src:*def\n"));
+  Files.push_back(makeSpecialCaseListFile("src:baz\n"
+                                          "src:car\n"
+                                          "src:def*"));
+  auto SCL = SpecialCaseList::createOrDie(Files, *vfs::getRealFileSystem());
+  EXPECT_THAT(SCL->inSectionBlame("", "src", "bar"), Pair(0u, 1u));
+  EXPECT_THAT(SCL->inSectionBlame("", "src", "fooaaaaaa"), Pair(0u, 2u));
+  EXPECT_THAT(SCL->inSectionBlame("", "src", "ban", "init"), Pair(0u, 3u));
+  EXPECT_THAT(SCL->inSectionBlame("", "src", "baz"), Pair(1u, 1u));
+  EXPECT_THAT(SCL->inSectionBlame("", "src", "car"), Pair(1u, 2u));
+  EXPECT_THAT(SCL->inSectionBlame("", "src", "aaaadef"), Pair(0u, 5u));
+  EXPECT_THAT(SCL->inSectionBlame("", "src", "defaaaaa"), Pair(1u, 3u));
+  for (auto &Path : Files)
+    sys::fs::remove(Path);
 }
+
+} // namespace


Reviews:
user: login: vitalybuka
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-28T02:10:29Z
user: login: vitalybuka
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-28T02:10:39Z
user: login: vitalybuka
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-28T02:11:45Z
user: login: vitalybuka
body: Please double check and merge
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-05-28T03:03:41Z
user: login: qinkunbao
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-28T03:21:39Z
user: login: vitalybuka
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-28T04:20:26Z

Review comments:
diff_hunk: @@ -145,12 +146,14 @@ class SpecialCaseList {
     Section(std::unique_ptr<Matcher> M) : SectionMatcher(std::move(M)) {};
     Section() : Section(std::make_unique<Matcher>()) {};
 
+    unsigned FileIdx;
     std::unique_ptr<Matcher> SectionMatcher;
     SectionEntries Entries;
     std::string SectionStr;
   };
 
   std::vector<Section> Sections;
+  unsigned currFileIdx;
path: llvm/include/llvm/Support/SpecialCaseList.h
user: login: vitalybuka
body: we don't need this as part of the state

please add another argument into `addSection(fileIdx)` and `parse(fileIdx)`
created_at: 2025-05-28T02:10:29Z
author_association: COLLABORATOR
diff_hunk: @@ -122,6 +123,7 @@ bool SpecialCaseList::createInternal(const std::vector<std::string> &Paths,
 
 bool SpecialCaseList::createInternal(const MemoryBuffer *MB,
                                      std::string &Error) {
+  ++currFileIdx;
path: llvm/lib/Support/SpecialCaseList.cpp
user: login: vitalybuka
body: MemoryBuffer is always one, let's make it 0
created_at: 2025-05-28T02:10:38Z
author_association: COLLABORATOR
diff_hunk: @@ -112,6 +112,7 @@ bool SpecialCaseList::createInternal(const std::vector<std::string> &Paths,
       return false;
     }
     std::string ParseError;
+    ++currFileIdx;
path: llvm/lib/Support/SpecialCaseList.cpp
user: login: vitalybuka
body: Wouild be nice to match idx in Paths array

`for (const auto &Path : Paths)` -> `for (unsigned Idx = 0; ....)`
created_at: 2025-05-28T02:11:44Z
author_association: COLLABORATOR
diff_hunk: @@ -70,7 +70,7 @@ class FileSystem;
 /// ---
 class SpecialCaseList {
 public:
-  constexpr static std::pair<unsigned, unsigned> NotFound = {0, 0};
+  static constexpr std::pair<unsigned, unsigned> NotFound = {0, 0};
path: llvm/include/llvm/Support/SpecialCaseList.h
user: login: qinkunbao
body: I thought static constexpr and constexpr static mean exactly the same thing
created_at: 2025-05-28T03:21:39Z
author_association: MEMBER
diff_hunk: @@ -70,7 +70,7 @@ class FileSystem;
 /// ---
 class SpecialCaseList {
 public:
-  constexpr static std::pair<unsigned, unsigned> NotFound = {0, 0};
+  static constexpr std::pair<unsigned, unsigned> NotFound = {0, 0};
path: llvm/include/llvm/Support/SpecialCaseList.h
user: login: vitalybuka
body: yes, for consistency
created_at: 2025-05-28T04:20:25Z
author_association: COLLABORATOR

PR comments:
user: login: llvmbot
created_at: 2025-05-27T02:37:05Z
body: 
<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-support

Author: Qinkun Bao (qinkunbao)

<details>
<summary>Changes</summary>

Accoring to the discussion in
https://github.com/llvm/llvm-project/pull/140529, we need to SSCL can be
created from multiple ignore list files, so we can repeat
-fsanitize-ignorelist=. The change is necessary to achieve the feature
described in https://github.com/llvm/llvm-project/issues/139128.


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


4 Files Affected:

- (modified) llvm/include/llvm/Support/SpecialCaseList.h (+9-6) 
- (modified) llvm/lib/Support/SpecialCaseList.cpp (+10-6) 
- (modified) llvm/tools/llvm-cfi-verify/llvm-cfi-verify.cpp (+9-6) 
- (modified) llvm/unittests/Support/SpecialCaseListTest.cpp (+45-17) 


``````````diff
diff --git a/llvm/include/llvm/Support/SpecialCaseList.h b/llvm/include/llvm/Support/SpecialCaseList.h
index 653a3b14ebf03..bce337f553a93 100644
--- a/llvm/include/llvm/Support/SpecialCaseList.h
+++ b/llvm/include/llvm/Support/SpecialCaseList.h
@@ -17,6 +17,7 @@
 #include "llvm/Support/GlobPattern.h"
 #include "llvm/Support/Regex.h"
 #include <memory>
+#include <utility>
 #include <string>
 #include <vector>
 
@@ -93,17 +94,17 @@ class SpecialCaseList {
   LLVM_ABI bool inSection(StringRef Section, StringRef Prefix, StringRef Query,
                           StringRef Category = StringRef()) const;
 
-  /// Returns the line number corresponding to the special case list entry if
-  /// the special case list contains a line
+  /// Returns the file index and the line numebr <FileIdx, LineNo> corresponding
+  /// to the special case list entry if the special case list contains a line
   /// \code
   ///   @Prefix:<E>=@Category
   /// \endcode
   /// where @Query satisfies the glob <E> in a given @Section.
-  /// Returns zero if there is no exclusion entry corresponding to this
+  /// Returns (zero, zero) if there is no exclusion entry corresponding to this
   /// expression.
-  LLVM_ABI unsigned inSectionBlame(StringRef Section, StringRef Prefix,
-                                   StringRef Query,
-                                   StringRef Category = StringRef()) const;
+  LLVM_ABI std::pair<unsigned, unsigned>
+  inSectionBlame(StringRef Section, StringRef Prefix, StringRef Query,
+                 StringRef Category = StringRef()) const;
 
 protected:
   // Implementations of the create*() functions that can also be used by derived
@@ -145,12 +146,14 @@ class SpecialCaseList {
     Section(std::unique_ptr<Matcher> M) : SectionMatcher(std::move(M)) {};
     Section() : Section(std::make_unique<Matcher>()) {};
 
+    unsigned FileIdx;
     std::unique_ptr<Matcher> SectionMatcher;
     SectionEntries Entries;
     std::string SectionStr;
   };
 
   std::vector<Section> Sections;
+  unsigned currFileIdx;
 
   LLVM_ABI Expected<Section *> addSection(StringRef SectionStr, unsigned LineNo,
                                           bool UseGlobs = true);
diff --git a/llvm/lib/Support/SpecialCaseList.cpp b/llvm/lib/Support/SpecialCaseList.cpp
index 56327b56282c2..5a66f163d7913 100644
--- a/llvm/lib/Support/SpecialCaseList.cpp
+++ b/llvm/lib/Support/SpecialCaseList.cpp
@@ -112,6 +112,7 @@ bool SpecialCaseList::createInternal(const std::vector<std::string> &Paths,
       return false;
     }
     std::string ParseError;
+    ++currFileIdx;
     if (!parse(FileOrErr.get().get(), ParseError)) {
       Error = (Twine("error parsing file '") + Path + "': " + ParseError).str();
       return false;
@@ -122,6 +123,7 @@ bool SpecialCaseList::createInternal(const std::vector<std::string> &Paths,
 
 bool SpecialCaseList::createInternal(const MemoryBuffer *MB,
                                      std::string &Error) {
+  ++currFileIdx;
   if (!parse(MB, Error))
     return false;
   return true;
@@ -133,6 +135,7 @@ SpecialCaseList::addSection(StringRef SectionStr, unsigned LineNo,
   Sections.emplace_back();
   auto &Section = Sections.back();
   Section.SectionStr = SectionStr;
+  Section.FileIdx = currFileIdx;
 
   if (auto Err = Section.SectionMatcher->insert(SectionStr, LineNo, UseGlobs)) {
     return createStringError(errc::invalid_argument,
@@ -207,20 +210,21 @@ SpecialCaseList::~SpecialCaseList() = default;
 
 bool SpecialCaseList::inSection(StringRef Section, StringRef Prefix,
                                 StringRef Query, StringRef Category) const {
-  return inSectionBlame(Section, Prefix, Query, Category);
+  auto [FileIdx, LineNo] = inSectionBlame(Section, Prefix, Query, Category);
+  return LineNo;
 }
 
-unsigned SpecialCaseList::inSectionBlame(StringRef Section, StringRef Prefix,
-                                         StringRef Query,
-                                         StringRef Category) const {
+std::pair<unsigned, unsigned>
+SpecialCaseList::inSectionBlame(StringRef Section, StringRef Prefix,
+                                StringRef Query, StringRef Category) const {
   for (auto it = Sections.crbegin(); it != Sections.crend(); ++it) {
     if (it->SectionMatcher->match(Section)) {
       unsigned Blame = inSectionBlame(it->Entries, Prefix, Query, Category);
       if (Blame)
-        return Blame;
+        return {it->FileIdx, Blame};
     }
   }
-  return 0;
+  return {0, 0};
 }
 
 unsigned SpecialCaseList::inSectionBlame(const SectionEntries &Entries,
diff --git a/llvm/tools/llvm-cfi-verify/llvm-cfi-verify.cpp b/llvm/tools/llvm-cfi-verify/llvm-cfi-verify.cpp
index 0f2c7da94230e..b372957204691 100644
--- a/llvm/tools/llvm-cfi-verify/llvm-cfi-verify.cpp
+++ b/llvm/tools/llvm-cfi-verify/llvm-cfi-verify.cpp
@@ -78,8 +78,7 @@ static void printBlameContext(const DILineInfo &LineInfo, unsigned Context) {
   File->getBuffer().split(Lines, '\n');
 
   for (unsigned i = std::max<size_t>(1, LineInfo.Line - Context);
-       i <
-       std::min<size_t>(Lines.size() + 1, LineInfo.Line + Context + 1);
+       i < std::min<size_t>(Lines.size() + 1, LineInfo.Line + Context + 1);
        ++i) {
     if (i == LineInfo.Line)
       outs() << ">";
@@ -193,12 +192,16 @@ printIndirectCFInstructions(FileAnalysis &Analysis,
 
     unsigned BlameLine = 0;
     for (auto &K : {"cfi-icall", "cfi-vcall"}) {
-      if (!BlameLine)
-        BlameLine =
+      if (!BlameLine) {
+        auto [FileIdx, Line] =
             SpecialCaseList->inSectionBlame(K, "src", LineInfo.FileName);
-      if (!BlameLine)
-        BlameLine =
+        BlameLine = Line;
+      }
+      if (!BlameLine) {
+        auto [FileIdx, Line] =
             SpecialCaseList->inSectionBlame(K, "fun", LineInfo.FunctionName);
+        BlameLine = Line;
+      }
     }
 
     if (BlameLine) {
diff --git a/llvm/unittests/Support/SpecialCaseListTest.cpp b/llvm/unittests/Support/SpecialCaseListTest.cpp
index ce58328f396b6..da4c557e740e6 100644
--- a/llvm/unittests/Support/SpecialCaseListTest.cpp
+++ b/llvm/unittests/Support/SpecialCaseListTest.cpp
@@ -14,6 +14,7 @@
 #include "gtest/gtest.h"
 
 using testing::HasSubstr;
+using testing::Pair;
 using testing::StartsWith;
 using namespace llvm;
 
@@ -70,13 +71,14 @@ TEST_F(SpecialCaseListTest, Basic) {
   EXPECT_FALSE(SCL->inSection("", "fun", "hello"));
   EXPECT_FALSE(SCL->inSection("", "src", "hello", "category"));
 
-  EXPECT_EQ(3u, SCL->inSectionBlame("", "src", "hello"));
-  EXPECT_EQ(4u, SCL->inSectionBlame("", "src", "bye"));
-  EXPECT_EQ(5u, SCL->inSectionBlame("", "src", "hi", "category"));
-  EXPECT_EQ(6u, SCL->inSectionBlame("", "src", "zzzz", "category"));
-  EXPECT_EQ(0u, SCL->inSectionBlame("", "src", "hi"));
-  EXPECT_EQ(0u, SCL->inSectionBlame("", "fun", "hello"));
-  EXPECT_EQ(0u, SCL->inSectionBlame("", "src", "hello", "category"));
+  EXPECT_THAT(SCL->inSectionBlame("", "src", "hello"), Pair(1u, 3u));
+  EXPECT_THAT(SCL->inSectionBlame("", "src", "bye"), Pair(1u, 4u));
+  EXPECT_THAT(SCL->inSectionBlame("", "src", "hi", "category"), Pair(1u, 5u));
+  EXPECT_THAT(SCL->inSectionBlame("", "src", "zzzz", "category"), Pair(1u, 6u));
+  EXPECT_THAT(SCL->inSectionBlame("", "src", "hi"), Pair(0u, 0u));
+  EXPECT_THAT(SCL->inSectionBlame("", "fun", "hello"), Pair(0u, 0u));
+  EXPECT_THAT(SCL->inSectionBlame("", "src", "hello", "category"),
+              Pair(0u, 0u));
 }
 
 TEST_F(SpecialCaseListTest, CorrectErrorLineNumberWithBlankLine) {
@@ -216,8 +218,9 @@ TEST_F(SpecialCaseListTest, NoTrigramsInARule) {
 }
 
 TEST_F(SpecialCaseListTest, RepetitiveRule) {
-  std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("fun:*bar*bar*bar*bar*\n"
-                                                             "fun:bar*\n");
+  std::unique_ptr<SpecialCaseList> SCL =
+      makeSpecialCaseList("fun:*bar*bar*bar*bar*\n"
+                          "fun:bar*\n");
   EXPECT_TRUE(SCL->inSection("", "fun", "bara"));
   EXPECT_FALSE(SCL->inSection("", "fun", "abara"));
   EXPECT_TRUE(SCL->inSection("", "fun", "barbarbarbar"));
@@ -226,7 +229,8 @@ TEST_F(SpecialCaseListTest, RepetitiveRule) {
 }
 
 TEST_F(SpecialCaseListTest, SpecialSymbolRule) {
-  std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("src:*c\\+\\+abi*\n");
+  std::unique_ptr<SpecialCaseList> SCL =
+      makeSpecialCaseList("src:*c\\+\\+abi*\n");
   EXPECT_TRUE(SCL->inSection("", "src", "c++abi"));
   EXPECT_FALSE(SCL->inSection("", "src", "c\\+\\+abi"));
 }
@@ -242,8 +246,9 @@ TEST_F(SpecialCaseListTest, PopularTrigram) {
 }
 
 TEST_F(SpecialCaseListTest, EscapedSymbols) {
-  std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("src:*c\\+\\+abi*\n"
-                                                             "src:*hello\\\\world*\n");
+  std::unique_ptr<SpecialCaseList> SCL =
+      makeSpecialCaseList("src:*c\\+\\+abi*\n"
+                          "src:*hello\\\\world*\n");
   EXPECT_TRUE(SCL->inSection("", "src", "dir/c++abi"));
   EXPECT_FALSE(SCL->inSection("", "src", "dir/c\\+\\+abi"));
   EXPECT_FALSE(SCL->inSection("", "src", "c\\+\\+abi"));
@@ -323,10 +328,33 @@ TEST_F(SpecialCaseListTest, Version3) {
   EXPECT_TRUE(SCL->inSection("sect2", "src", "def"));
   EXPECT_TRUE(SCL->inSection("sect1", "src", "def"));
 
-  EXPECT_EQ(2u, SCL->inSectionBlame("sect1", "src", "fooz"));
-  EXPECT_EQ(4u, SCL->inSectionBlame("sect1", "src", "barz"));
-  EXPECT_EQ(5u, SCL->inSectionBlame("sect1", "src", "def"));
-  EXPECT_EQ(8u, SCL->inSectionBlame("sect2", "src", "def"));
-  EXPECT_EQ(8u, SCL->inSectionBlame("sect2", "src", "dez"));
+  EXPECT_THAT(SCL->inSectionBlame("sect1", "src", "fooz"), Pair(1u, 2u));
+  EXPECT_THAT(SCL->inSectionBlame("sect1", "src", "barz"), Pair(1u, 4u));
+  EXPECT_THAT(SCL->inSectionBlame("sect1", "src", "def"), Pair(1u, 5u));
+  EXPECT_THAT(SCL->inSectionBlame("sect2", "src", "def"), Pair(1u, 8u));
+  EXPECT_THAT(SCL->inSectionBlame("sect2", "src", "dez"), Pair(1u, 8u));
 }
+
+TEST_F(SpecialCaseListTest, FileIdx) {
+  std::vector<std::string> Files;
+  Files.push_back(makeSpecialCaseListFile("src:bar\n"
+                                          "src:*foo*\n"
+                                          "src:ban=init\n"
+                                          "src:baz\n"
+                                          "src:*def\n"));
+  Files.push_back(makeSpecialCaseListFile("src:baz\n"
+                                          "src:car\n"
+                                          "src:def*"));
+  auto SCL = SpecialCaseList::createOrDie(Files, *vfs::getRealFileSystem());
+  EXPECT_THAT(SCL->inSectionBlame("", "src", "bar"), Pair(1u, 1u));
+  EXPECT_THAT(SCL->inSectionBlame("", "src", "fooaaaaaa"), Pair(1u, 2u));
+  EXPECT_THAT(SCL->inSectionBlame("", "src", "ban", "init"), Pair(1u, 3u));
+  EXPECT_THAT(SCL->inSectionBlame("", "src", "baz"), Pair(2u, 1u));
+  EXPECT_THAT(SCL->inSectionBlame("", "src", "car"), Pair(2u, 2u));
+  EXPECT_THAT(SCL->inSectionBlame("", "src", "aaaadef"), Pair(1u, 5u));
+  EXPECT_THAT(SCL->inSectionBlame("", "src", "defaaaaa"), Pair(2u, 3u));
+  for (auto &Path : Files)
+    sys::fs::remove(Path);
 }
+
+} // namespace

``````````

</details>

author_association: MEMBER
user: login: github-actions[bot]
created_at: 2025-05-27T02:39:38Z
body: <!--LLVM CODE FORMAT COMMENT: {clang-format}-->

:white_check_mark: With the latest revision this PR passed the C/C++ code formatter.
author_association: NONE
user: login: vitalybuka
created_at: 2025-05-28T02:57:24Z
body: I have local changes, I'll push update

author_association: COLLABORATOR