Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ Potentially Breaking Changes
call the member ``operator delete`` instead of the expected global
delete operator. The old behavior is retained under ``-fclang-abi-compat=21``
flag.
- Clang warning suppressions file, ``--warning-suppression-mappings=``, now will
use the last matching entry instead of the longest one.
- Trailing null statements in GNU statement expressions are no longer
ignored by Clang; they now result in a void type. Clang previously
matched GCC's behavior, which was recently clarified to be incorrect.
Expand Down
4 changes: 2 additions & 2 deletions clang/docs/WarningSuppressionMappings.rst
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ Format
Warning suppression mappings uses the same format as
:doc:`SanitizerSpecialCaseList`.

Sections describe which diagnostic group's behaviour to change, e.g.
Sections describe which diagnostic group's behavior to change, e.g.
``[unused]``. When a diagnostic is matched by multiple sections, the latest
section takes precedence.

Expand All @@ -76,7 +76,7 @@ Source files are matched against these globs either:
- as paths relative to the current working directory
- as absolute paths.

When a source file matches multiple globs in a section, the longest one takes
When a source file matches multiple globs in a section, the last one takes
precedence.

.. code-block:: bash
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/Diagnostic.h
Original file line number Diff line number Diff line change
Expand Up @@ -971,7 +971,7 @@ class DiagnosticsEngine : public RefCountedBase<DiagnosticsEngine> {
/// diagnostics in specific files.
/// Mapping file is expected to be a special case list with sections denoting
/// diagnostic groups and `src` entries for globs to suppress. `emit` category
/// can be used to disable suppression. Longest glob that matches a filepath
/// can be used to disable suppression. The last glob that matches a filepath
/// takes precedence. For example:
/// [unused]
/// src:clang/*
Expand Down
14 changes: 5 additions & 9 deletions clang/lib/Basic/Diagnostic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -525,8 +525,7 @@ std::unique_ptr<WarningsSpecialCaseList>
WarningsSpecialCaseList::create(const llvm::MemoryBuffer &Input,
std::string &Err) {
auto WarningSuppressionList = std::make_unique<WarningsSpecialCaseList>();
if (!WarningSuppressionList->createInternal(&Input, Err,
/*OrderBySize=*/true))
if (!WarningSuppressionList->createInternal(&Input, Err))
return nullptr;
return WarningSuppressionList;
}
Expand Down Expand Up @@ -588,15 +587,12 @@ bool WarningsSpecialCaseList::isDiagSuppressed(diag::kind DiagId,

StringRef F = llvm::sys::path::remove_leading_dotslash(PLoc.getFilename());

StringRef LongestSup = DiagSection->getLongestMatch("src", F, "");
if (LongestSup.empty())
unsigned LastSup = DiagSection->getLastMatch("src", F, "");
if (LastSup == 0)
return false;

StringRef LongestEmit = DiagSection->getLongestMatch("src", F, "emit");
if (LongestEmit.empty())
return true;

return LongestSup.size() > LongestEmit.size();
unsigned LastEmit = DiagSection->getLastMatch("src", F, "emit");
return LastSup > LastEmit;
}

bool DiagnosticsEngine::isSuppressedViaMapping(diag::kind DiagId,
Expand Down
8 changes: 3 additions & 5 deletions clang/unittests/Basic/DiagnosticTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ TEST_F(SuppressionMappingTest, EmitCategoryIsExcluded) {
locForFile("foo.cpp")));
}

TEST_F(SuppressionMappingTest, LongestMatchWins) {
TEST_F(SuppressionMappingTest, LastMatchWins) {
llvm::StringLiteral SuppressionMappingFile = R"(
[unused]
src:*clang/*
Expand Down Expand Up @@ -327,10 +327,8 @@ TEST_F(SuppressionMappingTest, LongShortMatch) {

EXPECT_TRUE(Diags.isSuppressedViaMapping(diag::warn_unused_function,
locForFile("test/t1.cpp")));

// FIXME: This is confusing.
EXPECT_TRUE(Diags.isSuppressedViaMapping(diag::warn_unused_function,
locForFile("lld/test/t2.cpp")));
EXPECT_FALSE(Diags.isSuppressedViaMapping(diag::warn_unused_function,
locForFile("lld/test/t2.cpp")));
}

TEST_F(SuppressionMappingTest, ShortLongMatch) {
Expand Down
107 changes: 9 additions & 98 deletions llvm/include/llvm/Support/SpecialCaseList.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,11 @@
#ifndef LLVM_SUPPORT_SPECIALCASELIST_H
#define LLVM_SUPPORT_SPECIALCASELIST_H

#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/RadixTree.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/GlobPattern.h"
#include "llvm/Support/Regex.h"
#include "llvm/Support/Error.h"
#include <memory>
#include <string>
#include <utility>
#include <variant>
#include <vector>

namespace llvm {
Expand Down Expand Up @@ -118,90 +110,17 @@ class SpecialCaseList {
// classes.
LLVM_ABI bool createInternal(const std::vector<std::string> &Paths,
vfs::FileSystem &VFS, std::string &Error);
LLVM_ABI bool createInternal(const MemoryBuffer *MB, std::string &Error,
bool OrderBySize = false);
LLVM_ABI bool createInternal(const MemoryBuffer *MB, std::string &Error);

SpecialCaseList() = default;
SpecialCaseList(SpecialCaseList const &) = delete;
SpecialCaseList &operator=(SpecialCaseList const &) = delete;

private:
using Match = std::pair<StringRef, unsigned>;
static constexpr Match NotMatched = {"", 0};

// Lagacy v1 matcher.
class RegexMatcher {
public:
LLVM_ABI Error insert(StringRef Pattern, unsigned LineNumber);
LLVM_ABI void preprocess(bool BySize);

LLVM_ABI Match match(StringRef Query) const;

struct Reg {
Reg(StringRef Name, unsigned LineNo, Regex &&Rg)
: Name(Name), LineNo(LineNo), Rg(std::move(Rg)) {}
StringRef Name;
unsigned LineNo;
Regex Rg;
};

std::vector<Reg> RegExes;
};

class GlobMatcher {
public:
LLVM_ABI Error insert(StringRef Pattern, unsigned LineNumber);
LLVM_ABI void preprocess(bool BySize);

LLVM_ABI Match match(StringRef Query) const;

struct Glob {
Glob(StringRef Name, unsigned LineNo, GlobPattern &&Pattern)
: Name(Name), LineNo(LineNo), Pattern(std::move(Pattern)) {}
StringRef Name;
unsigned LineNo;
GlobPattern Pattern;
};

std::vector<GlobMatcher::Glob> Globs;

RadixTree<iterator_range<StringRef::const_iterator>,
RadixTree<iterator_range<StringRef::const_reverse_iterator>,
SmallVector<int, 1>>>
PrefixSuffixToGlob;

RadixTree<iterator_range<StringRef::const_iterator>, SmallVector<int, 1>>
SubstrToGlob;
};

/// Represents a set of patterns and their line numbers
class Matcher {
public:
LLVM_ABI Matcher(bool UseGlobs, bool RemoveDotSlash);

LLVM_ABI Error insert(StringRef Pattern, unsigned LineNumber);
LLVM_ABI void preprocess(bool BySize);

LLVM_ABI Match match(StringRef Query) const;

LLVM_ABI bool matchAny(StringRef Query) const {
return match(Query) != NotMatched;
}

std::variant<RegexMatcher, GlobMatcher> M;
bool RemoveDotSlash;
};

using SectionEntries = StringMap<StringMap<Matcher>>;

protected:
class Section {
public:
Section(StringRef Name, unsigned FileIdx, bool UseGlobs)
: SectionMatcher(UseGlobs, /*RemoveDotSlash=*/false), Name(Name),
FileIdx(FileIdx) {}

Section(Section &&) = default;
LLVM_ABI Section(StringRef Name, unsigned FileIdx, bool UseGlobs);
LLVM_ABI Section(Section &&);
LLVM_ABI ~Section();

// Returns name of the section, its entire string in [].
StringRef name() const { return Name; }
Expand All @@ -217,27 +136,19 @@ class SpecialCaseList {
LLVM_ABI unsigned getLastMatch(StringRef Prefix, StringRef Query,
StringRef Category) const;

// Helper method to search by Prefix, Query, and Category. Returns
// matching rule, or empty string if there is no match.
LLVM_ABI StringRef getLongestMatch(StringRef Prefix, StringRef Query,
StringRef Category) const;

/// Returns true if the section has any entries for the given prefix.
LLVM_ABI bool hasPrefix(StringRef Prefix) const;

private:
friend class SpecialCaseList;
LLVM_ABI void preprocess(bool OrderBySize);
LLVM_ABI const SpecialCaseList::Matcher *
findMatcher(StringRef Prefix, StringRef Category) const;
class SectionImpl;

Matcher SectionMatcher;
StringRef Name;
SectionEntries Entries;
unsigned FileIdx;
std::unique_ptr<SectionImpl> Impl;
};

ArrayRef<const Section> sections() const { return Sections; }
const std::vector<Section> &sections() const;

private:
BumpPtrAllocator StrAlloc;
Expand All @@ -249,7 +160,7 @@ class SpecialCaseList {

/// Parses just-constructed SpecialCaseList entries from a memory buffer.
LLVM_ABI bool parse(unsigned FileIdx, const MemoryBuffer *MB,
std::string &Error, bool OrderBySize);
std::string &Error);
};

} // namespace llvm
Expand Down
Loading
Loading