[clang] [clang codegen][regression] Add dso_local/hidden/etc. markings to VTT definitions and declarations (PR #72452)
https://github.com/justincady commented: LGTM as well, as the original fix remains in place. https://github.com/llvm/llvm-project/pull/72452 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Fix false-positives in misc-static-assert caused by non-constexpr variables (PR #77203)
https://github.com/justincady approved this pull request. Context: I have limited experience writing AST matchers, but I saw [the request for reviewers](https://discourse.llvm.org/t/clang-tidy-18-reviewers-wanted/76108). I'm basing this review on that limited experience and the tests put in place with this diff. On those grounds, these changes LGTM. https://github.com/llvm/llvm-project/pull/77203 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Fix false-positives in readability-container-size-empty (PR #74140)
https://github.com/justincady approved this pull request. [Context](https://github.com/llvm/llvm-project/pull/77203#pullrequestreview-1818501835). LGTM. https://github.com/llvm/llvm-project/pull/74140 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Add option to avoid generating coverage mappings for unused functions (PR #92582)
justincady wrote: @ZequanWu I tested your first suggestion (`-fprofile-list`) and I believe there's a bug preventing reduction of binary size. See https://github.com/llvm/llvm-project/issues/97588. https://github.com/llvm/llvm-project/pull/92582 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] Add option to exclude headers from clang-tidy analysis (PR #91400)
justincady wrote: @codectile `--exclude-header-filter` is used in conjunction with `--header-filter` to exclude certain headers from analysis. Check out the tests that were modified as a part of this PR for more examples, but the basic idea is: ``` $ clang-tidy --header-filter='.*' --exclude-header-filter='header1\.h' [...] ``` In that example all headers will be analyzed using the enabled checks _except_ `header1.h`. https://github.com/llvm/llvm-project/pull/91400 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] Add option to exclude headers from clang-tidy analysis (PR #91400)
https://github.com/justincady created https://github.com/llvm/llvm-project/pull/91400 This is a renewed attempt to land @toddlipcon's D34654. The comments on that patch indicate a broad desire for some ability to ignore headers. After considering various options, including migrating to std::regex, I believe this is the best path forward. It's intuitive to have separate regexes for including headers versus excluding them, and this approach has the added benefit of being completely opt-in. No existing configs will break, regardless of existing HeaderFilterRegex values. This functionality is useful for improving performance when analyzing a targeted subset of code, as well as in cases where some collection of headers cannot be modified (third party source, for example). >From a5de583aa94ef794a083c8b27df6dc6fc0762cb7 Mon Sep 17 00:00:00 2001 From: Justin Cady Date: Tue, 7 May 2024 16:54:35 -0400 Subject: [PATCH] Add option to exclude headers from clang-tidy analysis This is a renewed attempt to land @toddlipcon's D34654. The comments on that patch indicate a broad desire for some ability to ignore headers. After considering various options, including migrating to std::regex, I believe this is the best path forward. It's intuitive to have separate regexes for including headers versus excluding them, and this approach has the added benefit of being completely opt-in. No existing configs will break, regardless of existing HeaderFilterRegex values. This functionality is useful for improving performance when analyzing a targeted subset of code, as well as in cases where some collection of headers cannot be modified (third party source, for example). --- .../clang-tidy/ClangTidyDiagnosticConsumer.cpp | 10 +- .../clang-tidy/ClangTidyDiagnosticConsumer.h | 5 + .../clang-tidy/ClangTidyOptions.cpp | 4 clang-tools-extra/clang-tidy/ClangTidyOptions.h | 4 .../clang-tidy/tool/ClangTidyMain.cpp| 16 .../clang-tidy/infrastructure/file-filter.cpp| 7 +++ 6 files changed, 45 insertions(+), 1 deletion(-) diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp index de2a3b51422a5..3cde0d2d68874 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp @@ -564,7 +564,8 @@ void ClangTidyDiagnosticConsumer::checkFilters(SourceLocation Location, StringRef FileName(File->getName()); LastErrorRelatesToUserCode = LastErrorRelatesToUserCode || Sources.isInMainFile(Location) || - getHeaderFilter()->match(FileName); + (getHeaderFilter()->match(FileName) && +!getExcludeHeaderFilter()->match(FileName)); unsigned LineNumber = Sources.getExpansionLineNumber(Location); LastErrorPassesLineFilter = @@ -578,6 +579,13 @@ llvm::Regex *ClangTidyDiagnosticConsumer::getHeaderFilter() { return HeaderFilter.get(); } +llvm::Regex *ClangTidyDiagnosticConsumer::getExcludeHeaderFilter() { + if (!ExcludeHeaderFilter) +ExcludeHeaderFilter = std::make_unique( +*Context.getOptions().ExcludeHeaderFilterRegex); + return ExcludeHeaderFilter.get(); +} + void ClangTidyDiagnosticConsumer::removeIncompatibleErrors() { // Each error is modelled as the set of intervals in which it applies // replacements. To detect overlapping replacements, we use a sweep line diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h index 9280eb1e1f218..a3add5d52778d 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h +++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h @@ -299,6 +299,10 @@ class ClangTidyDiagnosticConsumer : public DiagnosticConsumer { /// context. llvm::Regex *getHeaderFilter(); + /// \brief Returns the \c ExcludeHeaderFilter constructed for the options set + /// in the context. + llvm::Regex *getExcludeHeaderFilter(); + /// Updates \c LastErrorRelatesToUserCode and LastErrorPassesLineFilter /// according to the diagnostic \p Location. void checkFilters(SourceLocation Location, const SourceManager &Sources); @@ -313,6 +317,7 @@ class ClangTidyDiagnosticConsumer : public DiagnosticConsumer { bool EnableNolintBlocks; std::vector Errors; std::unique_ptr HeaderFilter; + std::unique_ptr ExcludeHeaderFilter; bool LastErrorRelatesToUserCode = false; bool LastErrorPassesLineFilter = false; bool LastErrorWasIgnored = false; diff --git a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp b/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp index cbf21a0e2ae34..254ce7fc60fc9 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp @@ -170,6 +170,8 @
[clang-tools-extra] Add option to exclude headers from clang-tidy analysis (PR #91400)
justincady wrote: > I wonder what is the target scenario for this feature. This PR addresses clang-tidy's lack of ability to ignore some set of headers when analyzing a file (most commonly third party code that cannot be modified). > I remember regex can excluding some pattern, the we can exclude header file > in `HeaderFilterRegex`. The underlying regex implementation for `HeaderFilterRegex` is `llvm::Regex` which does not support negative lookahead. See: - https://reviews.llvm.org/D34654 - https://lists.llvm.org/pipermail/cfe-dev/2015-November/046203.html - https://github.com/llvm/llvm-project/issues/25590 As I mentioned in the description, one option to allow exclusion of headers would be migrating to `std::regex`. But I think that has the potential to break existing configs, which is why reviving/reimplementing D34654 seems like the best path forward to me. https://github.com/llvm/llvm-project/pull/91400 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] Add option to exclude headers from clang-tidy analysis (PR #91400)
@@ -578,6 +579,13 @@ llvm::Regex *ClangTidyDiagnosticConsumer::getHeaderFilter() { return HeaderFilter.get(); } +llvm::Regex *ClangTidyDiagnosticConsumer::getExcludeHeaderFilter() { + if (!ExcludeHeaderFilter) +ExcludeHeaderFilter = std::make_unique( +*Context.getOptions().ExcludeHeaderFilterRegex); justincady wrote: I'm not sure I follow here. If `ExcludeHeaderFilterRegex` isn't set via the command line or config, it will be initialized to an empty string. Then the `llvm::Regex` will be constructed with that empty string. Is that different than what you mean? https://github.com/llvm/llvm-project/pull/91400 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] Add option to exclude headers from clang-tidy analysis (PR #91400)
@@ -578,6 +579,13 @@ llvm::Regex *ClangTidyDiagnosticConsumer::getHeaderFilter() { return HeaderFilter.get(); } +llvm::Regex *ClangTidyDiagnosticConsumer::getExcludeHeaderFilter() { + if (!ExcludeHeaderFilter) +ExcludeHeaderFilter = std::make_unique( +*Context.getOptions().ExcludeHeaderFilterRegex); justincady wrote: Ok, thanks for clarifying. I will look into this. https://github.com/llvm/llvm-project/pull/91400 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] Add option to exclude headers from clang-tidy analysis (PR #91400)
https://github.com/justincady updated https://github.com/llvm/llvm-project/pull/91400 >From a5de583aa94ef794a083c8b27df6dc6fc0762cb7 Mon Sep 17 00:00:00 2001 From: Justin Cady Date: Tue, 7 May 2024 16:54:35 -0400 Subject: [PATCH 1/2] Add option to exclude headers from clang-tidy analysis This is a renewed attempt to land @toddlipcon's D34654. The comments on that patch indicate a broad desire for some ability to ignore headers. After considering various options, including migrating to std::regex, I believe this is the best path forward. It's intuitive to have separate regexes for including headers versus excluding them, and this approach has the added benefit of being completely opt-in. No existing configs will break, regardless of existing HeaderFilterRegex values. This functionality is useful for improving performance when analyzing a targeted subset of code, as well as in cases where some collection of headers cannot be modified (third party source, for example). --- .../clang-tidy/ClangTidyDiagnosticConsumer.cpp | 10 +- .../clang-tidy/ClangTidyDiagnosticConsumer.h | 5 + .../clang-tidy/ClangTidyOptions.cpp | 4 clang-tools-extra/clang-tidy/ClangTidyOptions.h | 4 .../clang-tidy/tool/ClangTidyMain.cpp| 16 .../clang-tidy/infrastructure/file-filter.cpp| 7 +++ 6 files changed, 45 insertions(+), 1 deletion(-) diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp index de2a3b51422a5..3cde0d2d68874 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp @@ -564,7 +564,8 @@ void ClangTidyDiagnosticConsumer::checkFilters(SourceLocation Location, StringRef FileName(File->getName()); LastErrorRelatesToUserCode = LastErrorRelatesToUserCode || Sources.isInMainFile(Location) || - getHeaderFilter()->match(FileName); + (getHeaderFilter()->match(FileName) && +!getExcludeHeaderFilter()->match(FileName)); unsigned LineNumber = Sources.getExpansionLineNumber(Location); LastErrorPassesLineFilter = @@ -578,6 +579,13 @@ llvm::Regex *ClangTidyDiagnosticConsumer::getHeaderFilter() { return HeaderFilter.get(); } +llvm::Regex *ClangTidyDiagnosticConsumer::getExcludeHeaderFilter() { + if (!ExcludeHeaderFilter) +ExcludeHeaderFilter = std::make_unique( +*Context.getOptions().ExcludeHeaderFilterRegex); + return ExcludeHeaderFilter.get(); +} + void ClangTidyDiagnosticConsumer::removeIncompatibleErrors() { // Each error is modelled as the set of intervals in which it applies // replacements. To detect overlapping replacements, we use a sweep line diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h index 9280eb1e1f218..a3add5d52778d 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h +++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h @@ -299,6 +299,10 @@ class ClangTidyDiagnosticConsumer : public DiagnosticConsumer { /// context. llvm::Regex *getHeaderFilter(); + /// \brief Returns the \c ExcludeHeaderFilter constructed for the options set + /// in the context. + llvm::Regex *getExcludeHeaderFilter(); + /// Updates \c LastErrorRelatesToUserCode and LastErrorPassesLineFilter /// according to the diagnostic \p Location. void checkFilters(SourceLocation Location, const SourceManager &Sources); @@ -313,6 +317,7 @@ class ClangTidyDiagnosticConsumer : public DiagnosticConsumer { bool EnableNolintBlocks; std::vector Errors; std::unique_ptr HeaderFilter; + std::unique_ptr ExcludeHeaderFilter; bool LastErrorRelatesToUserCode = false; bool LastErrorPassesLineFilter = false; bool LastErrorWasIgnored = false; diff --git a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp b/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp index cbf21a0e2ae34..254ce7fc60fc9 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp @@ -170,6 +170,8 @@ template <> struct MappingTraits { IO.mapOptional("ImplementationFileExtensions", Options.ImplementationFileExtensions); IO.mapOptional("HeaderFilterRegex", Options.HeaderFilterRegex); +IO.mapOptional("ExcludeHeaderFilterRegex", + Options.ExcludeHeaderFilterRegex); IO.mapOptional("FormatStyle", Options.FormatStyle); IO.mapOptional("User", Options.User); IO.mapOptional("CheckOptions", Options.CheckOptions); @@ -192,6 +194,7 @@ ClangTidyOptions ClangTidyOptions::getDefaults() { Options.HeaderFileExtensions = {"", "h", "hh", "hpp", "hxx"}; Options.ImplementationFileExtensions = {"c", "cc", "cpp", "cxx"}; Optio
[clang-tools-extra] Add option to exclude headers from clang-tidy analysis (PR #91400)
@@ -578,6 +579,13 @@ llvm::Regex *ClangTidyDiagnosticConsumer::getHeaderFilter() { return HeaderFilter.get(); } +llvm::Regex *ClangTidyDiagnosticConsumer::getExcludeHeaderFilter() { + if (!ExcludeHeaderFilter) +ExcludeHeaderFilter = std::make_unique( +*Context.getOptions().ExcludeHeaderFilterRegex); justincady wrote: I just pushed a commit that omits the check when `ExcludeHeaderFilter` is not set by the user. Please let me know if this aligns with your idea. https://github.com/llvm/llvm-project/pull/91400 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] Add option to exclude headers from clang-tidy analysis (PR #91400)
https://github.com/justincady updated https://github.com/llvm/llvm-project/pull/91400 >From a5de583aa94ef794a083c8b27df6dc6fc0762cb7 Mon Sep 17 00:00:00 2001 From: Justin Cady Date: Tue, 7 May 2024 16:54:35 -0400 Subject: [PATCH 1/3] Add option to exclude headers from clang-tidy analysis This is a renewed attempt to land @toddlipcon's D34654. The comments on that patch indicate a broad desire for some ability to ignore headers. After considering various options, including migrating to std::regex, I believe this is the best path forward. It's intuitive to have separate regexes for including headers versus excluding them, and this approach has the added benefit of being completely opt-in. No existing configs will break, regardless of existing HeaderFilterRegex values. This functionality is useful for improving performance when analyzing a targeted subset of code, as well as in cases where some collection of headers cannot be modified (third party source, for example). --- .../clang-tidy/ClangTidyDiagnosticConsumer.cpp | 10 +- .../clang-tidy/ClangTidyDiagnosticConsumer.h | 5 + .../clang-tidy/ClangTidyOptions.cpp | 4 clang-tools-extra/clang-tidy/ClangTidyOptions.h | 4 .../clang-tidy/tool/ClangTidyMain.cpp| 16 .../clang-tidy/infrastructure/file-filter.cpp| 7 +++ 6 files changed, 45 insertions(+), 1 deletion(-) diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp index de2a3b51422a5..3cde0d2d68874 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp @@ -564,7 +564,8 @@ void ClangTidyDiagnosticConsumer::checkFilters(SourceLocation Location, StringRef FileName(File->getName()); LastErrorRelatesToUserCode = LastErrorRelatesToUserCode || Sources.isInMainFile(Location) || - getHeaderFilter()->match(FileName); + (getHeaderFilter()->match(FileName) && +!getExcludeHeaderFilter()->match(FileName)); unsigned LineNumber = Sources.getExpansionLineNumber(Location); LastErrorPassesLineFilter = @@ -578,6 +579,13 @@ llvm::Regex *ClangTidyDiagnosticConsumer::getHeaderFilter() { return HeaderFilter.get(); } +llvm::Regex *ClangTidyDiagnosticConsumer::getExcludeHeaderFilter() { + if (!ExcludeHeaderFilter) +ExcludeHeaderFilter = std::make_unique( +*Context.getOptions().ExcludeHeaderFilterRegex); + return ExcludeHeaderFilter.get(); +} + void ClangTidyDiagnosticConsumer::removeIncompatibleErrors() { // Each error is modelled as the set of intervals in which it applies // replacements. To detect overlapping replacements, we use a sweep line diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h index 9280eb1e1f218..a3add5d52778d 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h +++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h @@ -299,6 +299,10 @@ class ClangTidyDiagnosticConsumer : public DiagnosticConsumer { /// context. llvm::Regex *getHeaderFilter(); + /// \brief Returns the \c ExcludeHeaderFilter constructed for the options set + /// in the context. + llvm::Regex *getExcludeHeaderFilter(); + /// Updates \c LastErrorRelatesToUserCode and LastErrorPassesLineFilter /// according to the diagnostic \p Location. void checkFilters(SourceLocation Location, const SourceManager &Sources); @@ -313,6 +317,7 @@ class ClangTidyDiagnosticConsumer : public DiagnosticConsumer { bool EnableNolintBlocks; std::vector Errors; std::unique_ptr HeaderFilter; + std::unique_ptr ExcludeHeaderFilter; bool LastErrorRelatesToUserCode = false; bool LastErrorPassesLineFilter = false; bool LastErrorWasIgnored = false; diff --git a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp b/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp index cbf21a0e2ae34..254ce7fc60fc9 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp @@ -170,6 +170,8 @@ template <> struct MappingTraits { IO.mapOptional("ImplementationFileExtensions", Options.ImplementationFileExtensions); IO.mapOptional("HeaderFilterRegex", Options.HeaderFilterRegex); +IO.mapOptional("ExcludeHeaderFilterRegex", + Options.ExcludeHeaderFilterRegex); IO.mapOptional("FormatStyle", Options.FormatStyle); IO.mapOptional("User", Options.User); IO.mapOptional("CheckOptions", Options.CheckOptions); @@ -192,6 +194,7 @@ ClangTidyOptions ClangTidyOptions::getDefaults() { Options.HeaderFileExtensions = {"", "h", "hh", "hpp", "hxx"}; Options.ImplementationFileExtensions = {"c", "cc", "cpp", "cxx"}; Optio
[clang-tools-extra] Add option to exclude headers from clang-tidy analysis (PR #91400)
@@ -562,9 +567,10 @@ void ClangTidyDiagnosticConsumer::checkFilters(SourceLocation Location, } StringRef FileName(File->getName()); - LastErrorRelatesToUserCode = LastErrorRelatesToUserCode || - Sources.isInMainFile(Location) || - getHeaderFilter()->match(FileName); + LastErrorRelatesToUserCode = + LastErrorRelatesToUserCode || Sources.isInMainFile(Location) || + (getHeaderFilter()->match(FileName) && + (ExcludeHeaderFilter ? !ExcludeHeaderFilter->match(FileName) : true)); justincady wrote: Thank you! Simplified that snippet and added the tests as suggested. https://github.com/llvm/llvm-project/pull/91400 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] Add option to exclude headers from clang-tidy analysis (PR #91400)
@@ -311,7 +311,12 @@ ClangTidyDiagnosticConsumer::ClangTidyDiagnosticConsumer( : Context(Ctx), ExternalDiagEngine(ExternalDiagEngine), RemoveIncompatibleErrors(RemoveIncompatibleErrors), GetFixesFromNotes(GetFixesFromNotes), - EnableNolintBlocks(EnableNolintBlocks) {} + EnableNolintBlocks(EnableNolintBlocks) { + + if (Context.getOptions().ExcludeHeaderFilterRegex) +ExcludeHeaderFilter = std::make_unique( +*Context.getOptions().ExcludeHeaderFilterRegex); +} justincady wrote: Well, in the initial PR `ExcludeHeaderFilter` mirrored `HeaderFilter` behavior exactly. I changed it because @PiotrZSL made a nearly identical comment to yours about saving the call to `match` on an empty regex (which I think is handled in the latest revision). I _could_ migrate `HeaderFilter` to mirror the new and improved `ExcludeHeaderFilter`...though I worry a bit about this change growing larger and larger. What do you think? https://github.com/llvm/llvm-project/pull/91400 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] Add option to exclude headers from clang-tidy analysis (PR #91400)
@@ -311,7 +311,12 @@ ClangTidyDiagnosticConsumer::ClangTidyDiagnosticConsumer( : Context(Ctx), ExternalDiagEngine(ExternalDiagEngine), RemoveIncompatibleErrors(RemoveIncompatibleErrors), GetFixesFromNotes(GetFixesFromNotes), - EnableNolintBlocks(EnableNolintBlocks) {} + EnableNolintBlocks(EnableNolintBlocks) { + + if (Context.getOptions().ExcludeHeaderFilterRegex) +ExcludeHeaderFilter = std::make_unique( +*Context.getOptions().ExcludeHeaderFilterRegex); justincady wrote: What makes you suspect it doesn't work? I did some testing by placing `abort()` in an else clause and it caused many unit tests to crash. That leads me to believe it remains `std::nullopt` when the option is not specified. I will do some more thorough testing to confirm. https://github.com/llvm/llvm-project/pull/91400 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] Add option to exclude headers from clang-tidy analysis (PR #91400)
https://github.com/justincady updated https://github.com/llvm/llvm-project/pull/91400 >From a5de583aa94ef794a083c8b27df6dc6fc0762cb7 Mon Sep 17 00:00:00 2001 From: Justin Cady Date: Tue, 7 May 2024 16:54:35 -0400 Subject: [PATCH 1/5] Add option to exclude headers from clang-tidy analysis This is a renewed attempt to land @toddlipcon's D34654. The comments on that patch indicate a broad desire for some ability to ignore headers. After considering various options, including migrating to std::regex, I believe this is the best path forward. It's intuitive to have separate regexes for including headers versus excluding them, and this approach has the added benefit of being completely opt-in. No existing configs will break, regardless of existing HeaderFilterRegex values. This functionality is useful for improving performance when analyzing a targeted subset of code, as well as in cases where some collection of headers cannot be modified (third party source, for example). --- .../clang-tidy/ClangTidyDiagnosticConsumer.cpp | 10 +- .../clang-tidy/ClangTidyDiagnosticConsumer.h | 5 + .../clang-tidy/ClangTidyOptions.cpp | 4 clang-tools-extra/clang-tidy/ClangTidyOptions.h | 4 .../clang-tidy/tool/ClangTidyMain.cpp| 16 .../clang-tidy/infrastructure/file-filter.cpp| 7 +++ 6 files changed, 45 insertions(+), 1 deletion(-) diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp index de2a3b51422a5..3cde0d2d68874 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp @@ -564,7 +564,8 @@ void ClangTidyDiagnosticConsumer::checkFilters(SourceLocation Location, StringRef FileName(File->getName()); LastErrorRelatesToUserCode = LastErrorRelatesToUserCode || Sources.isInMainFile(Location) || - getHeaderFilter()->match(FileName); + (getHeaderFilter()->match(FileName) && +!getExcludeHeaderFilter()->match(FileName)); unsigned LineNumber = Sources.getExpansionLineNumber(Location); LastErrorPassesLineFilter = @@ -578,6 +579,13 @@ llvm::Regex *ClangTidyDiagnosticConsumer::getHeaderFilter() { return HeaderFilter.get(); } +llvm::Regex *ClangTidyDiagnosticConsumer::getExcludeHeaderFilter() { + if (!ExcludeHeaderFilter) +ExcludeHeaderFilter = std::make_unique( +*Context.getOptions().ExcludeHeaderFilterRegex); + return ExcludeHeaderFilter.get(); +} + void ClangTidyDiagnosticConsumer::removeIncompatibleErrors() { // Each error is modelled as the set of intervals in which it applies // replacements. To detect overlapping replacements, we use a sweep line diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h index 9280eb1e1f218..a3add5d52778d 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h +++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h @@ -299,6 +299,10 @@ class ClangTidyDiagnosticConsumer : public DiagnosticConsumer { /// context. llvm::Regex *getHeaderFilter(); + /// \brief Returns the \c ExcludeHeaderFilter constructed for the options set + /// in the context. + llvm::Regex *getExcludeHeaderFilter(); + /// Updates \c LastErrorRelatesToUserCode and LastErrorPassesLineFilter /// according to the diagnostic \p Location. void checkFilters(SourceLocation Location, const SourceManager &Sources); @@ -313,6 +317,7 @@ class ClangTidyDiagnosticConsumer : public DiagnosticConsumer { bool EnableNolintBlocks; std::vector Errors; std::unique_ptr HeaderFilter; + std::unique_ptr ExcludeHeaderFilter; bool LastErrorRelatesToUserCode = false; bool LastErrorPassesLineFilter = false; bool LastErrorWasIgnored = false; diff --git a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp b/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp index cbf21a0e2ae34..254ce7fc60fc9 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp @@ -170,6 +170,8 @@ template <> struct MappingTraits { IO.mapOptional("ImplementationFileExtensions", Options.ImplementationFileExtensions); IO.mapOptional("HeaderFilterRegex", Options.HeaderFilterRegex); +IO.mapOptional("ExcludeHeaderFilterRegex", + Options.ExcludeHeaderFilterRegex); IO.mapOptional("FormatStyle", Options.FormatStyle); IO.mapOptional("User", Options.User); IO.mapOptional("CheckOptions", Options.CheckOptions); @@ -192,6 +194,7 @@ ClangTidyOptions ClangTidyOptions::getDefaults() { Options.HeaderFileExtensions = {"", "h", "hh", "hpp", "hxx"}; Options.ImplementationFileExtensions = {"c", "cc", "cpp", "cxx"}; Optio
[clang-tools-extra] Add option to exclude headers from clang-tidy analysis (PR #91400)
@@ -311,7 +311,12 @@ ClangTidyDiagnosticConsumer::ClangTidyDiagnosticConsumer( : Context(Ctx), ExternalDiagEngine(ExternalDiagEngine), RemoveIncompatibleErrors(RemoveIncompatibleErrors), GetFixesFromNotes(GetFixesFromNotes), - EnableNolintBlocks(EnableNolintBlocks) {} + EnableNolintBlocks(EnableNolintBlocks) { + + if (Context.getOptions().ExcludeHeaderFilterRegex) +ExcludeHeaderFilter = std::make_unique( +*Context.getOptions().ExcludeHeaderFilterRegex); justincady wrote: After further testing I came to understand what you meant and made this adjustment as suggested. https://github.com/llvm/llvm-project/pull/91400 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] Add option to exclude headers from clang-tidy analysis (PR #91400)
@@ -311,7 +311,12 @@ ClangTidyDiagnosticConsumer::ClangTidyDiagnosticConsumer( : Context(Ctx), ExternalDiagEngine(ExternalDiagEngine), RemoveIncompatibleErrors(RemoveIncompatibleErrors), GetFixesFromNotes(GetFixesFromNotes), - EnableNolintBlocks(EnableNolintBlocks) {} + EnableNolintBlocks(EnableNolintBlocks) { + + if (Context.getOptions().ExcludeHeaderFilterRegex) +ExcludeHeaderFilter = std::make_unique( +*Context.getOptions().ExcludeHeaderFilterRegex); +} justincady wrote: The change to make `HeaderFilter` mirror `ExcludeHeaderFilter` was not too bad, so I went ahead with it. I thought it might actually be better to do now while everything is fresh in my mind. 🙂 https://github.com/llvm/llvm-project/pull/91400 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] Add option to exclude headers from clang-tidy analysis (PR #91400)
https://github.com/justincady updated https://github.com/llvm/llvm-project/pull/91400 >From e65bd48ef896f3327a1397a1b2f6f0a34e3711d2 Mon Sep 17 00:00:00 2001 From: Justin Cady Date: Tue, 7 May 2024 16:54:35 -0400 Subject: [PATCH] Add option to exclude headers from clang-tidy analysis This is a renewed attempt to land @toddlipcon's D34654. The comments on that patch indicate a broad desire for some ability to ignore headers. After considering various options, including migrating to std::regex, I believe this is the best path forward. It's intuitive to have separate regexes for including headers versus excluding them, and this approach has the added benefit of being completely opt-in. No existing configs will break, regardless of existing HeaderFilterRegex values. This functionality is useful for improving performance when analyzing a targeted subset of code, as well as in cases where some collection of headers cannot be modified (third party source, for example). --- .../ClangTidyDiagnosticConsumer.cpp | 28 ++- .../clang-tidy/ClangTidyDiagnosticConsumer.h | 1 + .../clang-tidy/ClangTidyOptions.cpp | 6 +- .../clang-tidy/ClangTidyOptions.h | 4 + .../clang-tidy/tool/ClangTidyMain.cpp | 18 ++ .../clang-tidy/tool/run-clang-tidy.py | 13 + clang-tools-extra/docs/ReleaseNotes.rst | 2 + clang-tools-extra/docs/clang-tidy/index.rst | 235 +- .../Inputs/config-files/.clang-tidy | 1 + .../Inputs/config-files/1/.clang-tidy | 1 + .../Inputs/config-files/3/.clang-tidy | 1 + .../infrastructure/config-files.cpp | 15 +- .../clang-tidy/infrastructure/file-filter.cpp | 7 + 13 files changed, 206 insertions(+), 126 deletions(-) diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp index de2a3b51422a5..200bb87a5ac3c 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp @@ -311,7 +311,18 @@ ClangTidyDiagnosticConsumer::ClangTidyDiagnosticConsumer( : Context(Ctx), ExternalDiagEngine(ExternalDiagEngine), RemoveIncompatibleErrors(RemoveIncompatibleErrors), GetFixesFromNotes(GetFixesFromNotes), - EnableNolintBlocks(EnableNolintBlocks) {} + EnableNolintBlocks(EnableNolintBlocks) { + + if (Context.getOptions().HeaderFilterRegex && + !Context.getOptions().HeaderFilterRegex->empty()) +HeaderFilter = +std::make_unique(*Context.getOptions().HeaderFilterRegex); + + if (Context.getOptions().ExcludeHeaderFilterRegex && + !Context.getOptions().ExcludeHeaderFilterRegex->empty()) +ExcludeHeaderFilter = std::make_unique( +*Context.getOptions().ExcludeHeaderFilterRegex); +} void ClangTidyDiagnosticConsumer::finalizeLastError() { if (!Errors.empty()) { @@ -562,22 +573,17 @@ void ClangTidyDiagnosticConsumer::checkFilters(SourceLocation Location, } StringRef FileName(File->getName()); - LastErrorRelatesToUserCode = LastErrorRelatesToUserCode || - Sources.isInMainFile(Location) || - getHeaderFilter()->match(FileName); + LastErrorRelatesToUserCode = + LastErrorRelatesToUserCode || Sources.isInMainFile(Location) || + (HeaderFilter && + (HeaderFilter->match(FileName) && +!(ExcludeHeaderFilter && ExcludeHeaderFilter->match(FileName; unsigned LineNumber = Sources.getExpansionLineNumber(Location); LastErrorPassesLineFilter = LastErrorPassesLineFilter || passesLineFilter(FileName, LineNumber); } -llvm::Regex *ClangTidyDiagnosticConsumer::getHeaderFilter() { - if (!HeaderFilter) -HeaderFilter = -std::make_unique(*Context.getOptions().HeaderFilterRegex); - return HeaderFilter.get(); -} - void ClangTidyDiagnosticConsumer::removeIncompatibleErrors() { // Each error is modelled as the set of intervals in which it applies // replacements. To detect overlapping replacements, we use a sweep line diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h index 9280eb1e1f218..97e16a12febd0 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h +++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h @@ -313,6 +313,7 @@ class ClangTidyDiagnosticConsumer : public DiagnosticConsumer { bool EnableNolintBlocks; std::vector Errors; std::unique_ptr HeaderFilter; + std::unique_ptr ExcludeHeaderFilter; bool LastErrorRelatesToUserCode = false; bool LastErrorPassesLineFilter = false; bool LastErrorWasIgnored = false; diff --git a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp b/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp index cbf21a0e2ae34..445c7f85c900c 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp +++ b/clang-tools
[clang-tools-extra] Add option to exclude headers from clang-tidy analysis (PR #91400)
https://github.com/justincady updated https://github.com/llvm/llvm-project/pull/91400 >From e65bd48ef896f3327a1397a1b2f6f0a34e3711d2 Mon Sep 17 00:00:00 2001 From: Justin Cady Date: Tue, 7 May 2024 16:54:35 -0400 Subject: [PATCH 1/2] Add option to exclude headers from clang-tidy analysis This is a renewed attempt to land @toddlipcon's D34654. The comments on that patch indicate a broad desire for some ability to ignore headers. After considering various options, including migrating to std::regex, I believe this is the best path forward. It's intuitive to have separate regexes for including headers versus excluding them, and this approach has the added benefit of being completely opt-in. No existing configs will break, regardless of existing HeaderFilterRegex values. This functionality is useful for improving performance when analyzing a targeted subset of code, as well as in cases where some collection of headers cannot be modified (third party source, for example). --- .../ClangTidyDiagnosticConsumer.cpp | 28 ++- .../clang-tidy/ClangTidyDiagnosticConsumer.h | 1 + .../clang-tidy/ClangTidyOptions.cpp | 6 +- .../clang-tidy/ClangTidyOptions.h | 4 + .../clang-tidy/tool/ClangTidyMain.cpp | 18 ++ .../clang-tidy/tool/run-clang-tidy.py | 13 + clang-tools-extra/docs/ReleaseNotes.rst | 2 + clang-tools-extra/docs/clang-tidy/index.rst | 235 +- .../Inputs/config-files/.clang-tidy | 1 + .../Inputs/config-files/1/.clang-tidy | 1 + .../Inputs/config-files/3/.clang-tidy | 1 + .../infrastructure/config-files.cpp | 15 +- .../clang-tidy/infrastructure/file-filter.cpp | 7 + 13 files changed, 206 insertions(+), 126 deletions(-) diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp index de2a3b51422a5..200bb87a5ac3c 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp @@ -311,7 +311,18 @@ ClangTidyDiagnosticConsumer::ClangTidyDiagnosticConsumer( : Context(Ctx), ExternalDiagEngine(ExternalDiagEngine), RemoveIncompatibleErrors(RemoveIncompatibleErrors), GetFixesFromNotes(GetFixesFromNotes), - EnableNolintBlocks(EnableNolintBlocks) {} + EnableNolintBlocks(EnableNolintBlocks) { + + if (Context.getOptions().HeaderFilterRegex && + !Context.getOptions().HeaderFilterRegex->empty()) +HeaderFilter = +std::make_unique(*Context.getOptions().HeaderFilterRegex); + + if (Context.getOptions().ExcludeHeaderFilterRegex && + !Context.getOptions().ExcludeHeaderFilterRegex->empty()) +ExcludeHeaderFilter = std::make_unique( +*Context.getOptions().ExcludeHeaderFilterRegex); +} void ClangTidyDiagnosticConsumer::finalizeLastError() { if (!Errors.empty()) { @@ -562,22 +573,17 @@ void ClangTidyDiagnosticConsumer::checkFilters(SourceLocation Location, } StringRef FileName(File->getName()); - LastErrorRelatesToUserCode = LastErrorRelatesToUserCode || - Sources.isInMainFile(Location) || - getHeaderFilter()->match(FileName); + LastErrorRelatesToUserCode = + LastErrorRelatesToUserCode || Sources.isInMainFile(Location) || + (HeaderFilter && + (HeaderFilter->match(FileName) && +!(ExcludeHeaderFilter && ExcludeHeaderFilter->match(FileName; unsigned LineNumber = Sources.getExpansionLineNumber(Location); LastErrorPassesLineFilter = LastErrorPassesLineFilter || passesLineFilter(FileName, LineNumber); } -llvm::Regex *ClangTidyDiagnosticConsumer::getHeaderFilter() { - if (!HeaderFilter) -HeaderFilter = -std::make_unique(*Context.getOptions().HeaderFilterRegex); - return HeaderFilter.get(); -} - void ClangTidyDiagnosticConsumer::removeIncompatibleErrors() { // Each error is modelled as the set of intervals in which it applies // replacements. To detect overlapping replacements, we use a sweep line diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h index 9280eb1e1f218..97e16a12febd0 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h +++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h @@ -313,6 +313,7 @@ class ClangTidyDiagnosticConsumer : public DiagnosticConsumer { bool EnableNolintBlocks; std::vector Errors; std::unique_ptr HeaderFilter; + std::unique_ptr ExcludeHeaderFilter; bool LastErrorRelatesToUserCode = false; bool LastErrorPassesLineFilter = false; bool LastErrorWasIgnored = false; diff --git a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp b/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp index cbf21a0e2ae34..445c7f85c900c 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp +++ b/clang-t
[clang-tools-extra] Add option to exclude headers from clang-tidy analysis (PR #91400)
https://github.com/justincady updated https://github.com/llvm/llvm-project/pull/91400 >From e65bd48ef896f3327a1397a1b2f6f0a34e3711d2 Mon Sep 17 00:00:00 2001 From: Justin Cady Date: Tue, 7 May 2024 16:54:35 -0400 Subject: [PATCH 1/3] Add option to exclude headers from clang-tidy analysis This is a renewed attempt to land @toddlipcon's D34654. The comments on that patch indicate a broad desire for some ability to ignore headers. After considering various options, including migrating to std::regex, I believe this is the best path forward. It's intuitive to have separate regexes for including headers versus excluding them, and this approach has the added benefit of being completely opt-in. No existing configs will break, regardless of existing HeaderFilterRegex values. This functionality is useful for improving performance when analyzing a targeted subset of code, as well as in cases where some collection of headers cannot be modified (third party source, for example). --- .../ClangTidyDiagnosticConsumer.cpp | 28 ++- .../clang-tidy/ClangTidyDiagnosticConsumer.h | 1 + .../clang-tidy/ClangTidyOptions.cpp | 6 +- .../clang-tidy/ClangTidyOptions.h | 4 + .../clang-tidy/tool/ClangTidyMain.cpp | 18 ++ .../clang-tidy/tool/run-clang-tidy.py | 13 + clang-tools-extra/docs/ReleaseNotes.rst | 2 + clang-tools-extra/docs/clang-tidy/index.rst | 235 +- .../Inputs/config-files/.clang-tidy | 1 + .../Inputs/config-files/1/.clang-tidy | 1 + .../Inputs/config-files/3/.clang-tidy | 1 + .../infrastructure/config-files.cpp | 15 +- .../clang-tidy/infrastructure/file-filter.cpp | 7 + 13 files changed, 206 insertions(+), 126 deletions(-) diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp index de2a3b51422a5..200bb87a5ac3c 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp @@ -311,7 +311,18 @@ ClangTidyDiagnosticConsumer::ClangTidyDiagnosticConsumer( : Context(Ctx), ExternalDiagEngine(ExternalDiagEngine), RemoveIncompatibleErrors(RemoveIncompatibleErrors), GetFixesFromNotes(GetFixesFromNotes), - EnableNolintBlocks(EnableNolintBlocks) {} + EnableNolintBlocks(EnableNolintBlocks) { + + if (Context.getOptions().HeaderFilterRegex && + !Context.getOptions().HeaderFilterRegex->empty()) +HeaderFilter = +std::make_unique(*Context.getOptions().HeaderFilterRegex); + + if (Context.getOptions().ExcludeHeaderFilterRegex && + !Context.getOptions().ExcludeHeaderFilterRegex->empty()) +ExcludeHeaderFilter = std::make_unique( +*Context.getOptions().ExcludeHeaderFilterRegex); +} void ClangTidyDiagnosticConsumer::finalizeLastError() { if (!Errors.empty()) { @@ -562,22 +573,17 @@ void ClangTidyDiagnosticConsumer::checkFilters(SourceLocation Location, } StringRef FileName(File->getName()); - LastErrorRelatesToUserCode = LastErrorRelatesToUserCode || - Sources.isInMainFile(Location) || - getHeaderFilter()->match(FileName); + LastErrorRelatesToUserCode = + LastErrorRelatesToUserCode || Sources.isInMainFile(Location) || + (HeaderFilter && + (HeaderFilter->match(FileName) && +!(ExcludeHeaderFilter && ExcludeHeaderFilter->match(FileName; unsigned LineNumber = Sources.getExpansionLineNumber(Location); LastErrorPassesLineFilter = LastErrorPassesLineFilter || passesLineFilter(FileName, LineNumber); } -llvm::Regex *ClangTidyDiagnosticConsumer::getHeaderFilter() { - if (!HeaderFilter) -HeaderFilter = -std::make_unique(*Context.getOptions().HeaderFilterRegex); - return HeaderFilter.get(); -} - void ClangTidyDiagnosticConsumer::removeIncompatibleErrors() { // Each error is modelled as the set of intervals in which it applies // replacements. To detect overlapping replacements, we use a sweep line diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h index 9280eb1e1f218..97e16a12febd0 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h +++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h @@ -313,6 +313,7 @@ class ClangTidyDiagnosticConsumer : public DiagnosticConsumer { bool EnableNolintBlocks; std::vector Errors; std::unique_ptr HeaderFilter; + std::unique_ptr ExcludeHeaderFilter; bool LastErrorRelatesToUserCode = false; bool LastErrorPassesLineFilter = false; bool LastErrorWasIgnored = false; diff --git a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp b/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp index cbf21a0e2ae34..445c7f85c900c 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp +++ b/clang-t
[clang-tools-extra] Add option to exclude headers from clang-tidy analysis (PR #91400)
https://github.com/justincady updated https://github.com/llvm/llvm-project/pull/91400 >From 58d3d52c666bdaa3534cd16080bb895d49f61008 Mon Sep 17 00:00:00 2001 From: Justin Cady Date: Tue, 7 May 2024 16:54:35 -0400 Subject: [PATCH] Add option to exclude headers from clang-tidy analysis This is a renewed attempt to land @toddlipcon's D34654. The comments on that patch indicate a broad desire for some ability to ignore headers. After considering various options, including migrating to std::regex, I believe this is the best path forward. It's intuitive to have separate regexes for including headers versus excluding them, and this approach has the added benefit of being completely opt-in. No existing configs will break, regardless of existing HeaderFilterRegex values. This functionality is useful for improving performance when analyzing a targeted subset of code, as well as in cases where some collection of headers cannot be modified (third party source, for example). --- .../ClangTidyDiagnosticConsumer.cpp | 28 ++- .../clang-tidy/ClangTidyDiagnosticConsumer.h | 1 + .../clang-tidy/ClangTidyOptions.cpp | 6 +- .../clang-tidy/ClangTidyOptions.h | 4 + .../clang-tidy/tool/ClangTidyMain.cpp | 18 ++ .../clang-tidy/tool/run-clang-tidy.py | 13 + clang-tools-extra/docs/ReleaseNotes.rst | 3 + clang-tools-extra/docs/clang-tidy/index.rst | 235 +- .../Inputs/config-files/.clang-tidy | 1 + .../Inputs/config-files/1/.clang-tidy | 1 + .../Inputs/config-files/3/.clang-tidy | 1 + .../infrastructure/config-files.cpp | 15 +- .../clang-tidy/infrastructure/file-filter.cpp | 7 + 13 files changed, 207 insertions(+), 126 deletions(-) diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp index de2a3b51422a5..200bb87a5ac3c 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp @@ -311,7 +311,18 @@ ClangTidyDiagnosticConsumer::ClangTidyDiagnosticConsumer( : Context(Ctx), ExternalDiagEngine(ExternalDiagEngine), RemoveIncompatibleErrors(RemoveIncompatibleErrors), GetFixesFromNotes(GetFixesFromNotes), - EnableNolintBlocks(EnableNolintBlocks) {} + EnableNolintBlocks(EnableNolintBlocks) { + + if (Context.getOptions().HeaderFilterRegex && + !Context.getOptions().HeaderFilterRegex->empty()) +HeaderFilter = +std::make_unique(*Context.getOptions().HeaderFilterRegex); + + if (Context.getOptions().ExcludeHeaderFilterRegex && + !Context.getOptions().ExcludeHeaderFilterRegex->empty()) +ExcludeHeaderFilter = std::make_unique( +*Context.getOptions().ExcludeHeaderFilterRegex); +} void ClangTidyDiagnosticConsumer::finalizeLastError() { if (!Errors.empty()) { @@ -562,22 +573,17 @@ void ClangTidyDiagnosticConsumer::checkFilters(SourceLocation Location, } StringRef FileName(File->getName()); - LastErrorRelatesToUserCode = LastErrorRelatesToUserCode || - Sources.isInMainFile(Location) || - getHeaderFilter()->match(FileName); + LastErrorRelatesToUserCode = + LastErrorRelatesToUserCode || Sources.isInMainFile(Location) || + (HeaderFilter && + (HeaderFilter->match(FileName) && +!(ExcludeHeaderFilter && ExcludeHeaderFilter->match(FileName; unsigned LineNumber = Sources.getExpansionLineNumber(Location); LastErrorPassesLineFilter = LastErrorPassesLineFilter || passesLineFilter(FileName, LineNumber); } -llvm::Regex *ClangTidyDiagnosticConsumer::getHeaderFilter() { - if (!HeaderFilter) -HeaderFilter = -std::make_unique(*Context.getOptions().HeaderFilterRegex); - return HeaderFilter.get(); -} - void ClangTidyDiagnosticConsumer::removeIncompatibleErrors() { // Each error is modelled as the set of intervals in which it applies // replacements. To detect overlapping replacements, we use a sweep line diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h index 9280eb1e1f218..97e16a12febd0 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h +++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h @@ -313,6 +313,7 @@ class ClangTidyDiagnosticConsumer : public DiagnosticConsumer { bool EnableNolintBlocks; std::vector Errors; std::unique_ptr HeaderFilter; + std::unique_ptr ExcludeHeaderFilter; bool LastErrorRelatesToUserCode = false; bool LastErrorPassesLineFilter = false; bool LastErrorWasIgnored = false; diff --git a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp b/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp index cbf21a0e2ae34..445c7f85c900c 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp +++ b/clang-tools
[clang-tools-extra] Add option to exclude headers from clang-tidy analysis (PR #91400)
https://github.com/justincady closed https://github.com/llvm/llvm-project/pull/91400 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] Add option to exclude headers from clang-tidy analysis (PR #91400)
justincady wrote: @Baiyi27 Could you please file an issue as opposed to adding it as a comment here? It may or may not be related to this original change, and separating it out into its own discussion would be helpful. Thanks! https://github.com/llvm/llvm-project/pull/91400 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [compiler-rt] Revert "[Coverage] Fix region termination for GNU statement expressions" (PR #132095)
https://github.com/justincady created https://github.com/llvm/llvm-project/pull/132095 Reverts llvm/llvm-project#130976 Breaks clang-cmake-x86_64-avx512-linux bot. >From 2f37c9ec685b8ba82fdc3bd8387ce59b3f8a77dc Mon Sep 17 00:00:00 2001 From: Justin Cady Date: Wed, 19 Mar 2025 16:45:26 -0400 Subject: [PATCH] =?UTF-8?q?Revert=20"[Coverage]=20Fix=20region=20terminati?= =?UTF-8?q?on=20for=20GNU=20statement=20expressions=20(#130=E2=80=A6"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 0827e3aae6eb69c2a6fa842ffa780881feb45b5d. --- clang/lib/CodeGen/CoverageMappingGen.cpp | 8 --- .../CoverageMapping/terminate-statements.cpp | 7 --- .../Linux/coverage-statement-expression.cpp | 21 --- 3 files changed, 36 deletions(-) delete mode 100644 compiler-rt/test/profile/Linux/coverage-statement-expression.cpp diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp index 73811d15979d5..f09157771d2b5 100644 --- a/clang/lib/CodeGen/CoverageMappingGen.cpp +++ b/clang/lib/CodeGen/CoverageMappingGen.cpp @@ -1505,14 +1505,6 @@ struct CounterCoverageMappingBuilder handleFileExit(getEnd(S)); } - void VisitStmtExpr(const StmtExpr *E) { -Visit(E->getSubStmt()); -// Any region termination (such as a noreturn CallExpr) within the statement -// expression has been handled by visiting the sub-statement. The visitor -// cannot be at a terminate statement leaving the statement expression. -HasTerminateStmt = false; - } - void VisitDecl(const Decl *D) { Stmt *Body = D->getBody(); diff --git a/clang/test/CoverageMapping/terminate-statements.cpp b/clang/test/CoverageMapping/terminate-statements.cpp index 3f8e43f0fbcb6..0067185fee8e6 100644 --- a/clang/test/CoverageMapping/terminate-statements.cpp +++ b/clang/test/CoverageMapping/terminate-statements.cpp @@ -346,12 +346,6 @@ int elsecondnoret(void) { return 0; } -// CHECK-LABEL: _Z18statementexprnoretb -int statementexprnoret(bool crash) { - int rc = ({ if (crash) abort(); 0; }); // CHECK: File 0, 351:35 -> 352:12 = (#0 - #1) - return rc; // CHECK-NOT: Gap -} - int main() { foo(0); foo(1); @@ -374,6 +368,5 @@ int main() { ornoret(); abstractcondnoret(); elsecondnoret(); - statementexprnoret(false); return 0; } diff --git a/compiler-rt/test/profile/Linux/coverage-statement-expression.cpp b/compiler-rt/test/profile/Linux/coverage-statement-expression.cpp deleted file mode 100644 index 7c76555e3300b..0 --- a/compiler-rt/test/profile/Linux/coverage-statement-expression.cpp +++ /dev/null @@ -1,21 +0,0 @@ -// RUN: %clangxx_profgen -std=gnu++17 -fuse-ld=lld -fcoverage-mapping -o %t %s -// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t -// RUN: llvm-profdata merge -o %t.profdata %t.profraw -// RUN: llvm-cov show %t -instr-profile=%t.profdata 2>&1 | FileCheck %s - -#include - -// clang-format off -__attribute__ ((__noreturn__)) -void foo(void) { while (1); } // CHECK: [[@LINE]]| 0|void foo(void) -_Noreturn void bar(void) { while (1); } // CHECK: [[@LINE]]| 0|_Noreturn void bar(void) -// CHECK: [[@LINE]]| | -int main(int argc, char **argv) { // CHECK: [[@LINE]]| 1|int main( - int rc = ({ if (argc > 3) foo(); 0; }); // CHECK: [[@LINE]]| 1| int rc = - printf("coverage after foo is present\n");// CHECK: [[@LINE]]| 1| printf( -// CHECK: [[@LINE]]| | - int rc2 = ({ if (argc > 3) bar(); 0; }); // CHECK: [[@LINE]]| 1| int rc2 = - printf("coverage after bar is present\n");// CHECK: [[@LINE]]| 1| printf( - return rc + rc2; // CHECK: [[@LINE]]| 1| return rc -} // CHECK: [[@LINE]]| 1|} -// clang-format on ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [compiler-rt] [Coverage] Fix region termination for GNU statement expressions (PR #130976)
https://github.com/justincady closed https://github.com/llvm/llvm-project/pull/130976 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [compiler-rt] Reland [Coverage] Fix region termination for GNU statement expressions (PR #132222)
https://github.com/justincady closed https://github.com/llvm/llvm-project/pull/13 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [compiler-rt] [Coverage] Fix region termination for GNU statement expressions (PR #130976)
https://github.com/justincady updated https://github.com/llvm/llvm-project/pull/130976 >From 6f3557780d06d6a2b1a7f315c49a3ad533d821e5 Mon Sep 17 00:00:00 2001 From: Justin Cady Date: Wed, 12 Mar 2025 11:23:19 -0400 Subject: [PATCH 1/3] [Coverage] Fix region termination for GNU statement expressions Calls to __noreturn__ functions result in region termination for coverage mapping. But this creates incorrect coverage results when __noreturn__ functions (or other constructs that result in region termination) occur within [GNU statement expressions][1]. In this scenario an extra gap region is introduced within VisitStmt, such that if the following line does not introduce a new region it is unconditionally counted as uncovered. This change adjusts the mapping such that terminate statements within statement expressions do not propagate that termination state after the statement expression is processed. [1]: https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html Fixes #124296 --- clang/lib/CodeGen/CoverageMappingGen.cpp | 8 .../CoverageMapping/terminate-statements.cpp | 7 +++ .../Linux/coverage-statement-expression.cpp | 19 +++ 3 files changed, 34 insertions(+) create mode 100644 compiler-rt/test/profile/Linux/coverage-statement-expression.cpp diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp index f09157771d2b5..73811d15979d5 100644 --- a/clang/lib/CodeGen/CoverageMappingGen.cpp +++ b/clang/lib/CodeGen/CoverageMappingGen.cpp @@ -1505,6 +1505,14 @@ struct CounterCoverageMappingBuilder handleFileExit(getEnd(S)); } + void VisitStmtExpr(const StmtExpr *E) { +Visit(E->getSubStmt()); +// Any region termination (such as a noreturn CallExpr) within the statement +// expression has been handled by visiting the sub-statement. The visitor +// cannot be at a terminate statement leaving the statement expression. +HasTerminateStmt = false; + } + void VisitDecl(const Decl *D) { Stmt *Body = D->getBody(); diff --git a/clang/test/CoverageMapping/terminate-statements.cpp b/clang/test/CoverageMapping/terminate-statements.cpp index 0067185fee8e6..d03e35630b317 100644 --- a/clang/test/CoverageMapping/terminate-statements.cpp +++ b/clang/test/CoverageMapping/terminate-statements.cpp @@ -346,6 +346,12 @@ int elsecondnoret(void) { return 0; } +// CHECK-LABEL: _Z18statementexprnoretb +int statementexprnoret(bool crash) { + int rc = ({ if (crash) abort(); 0; }); // CHECK-NOT: Gap,File 0, [[@LINE]]:41 -> [[@LINE+1]]:3 = 0 + return rc; +} + int main() { foo(0); foo(1); @@ -368,5 +374,6 @@ int main() { ornoret(); abstractcondnoret(); elsecondnoret(); + statementexprnoret(false); return 0; } diff --git a/compiler-rt/test/profile/Linux/coverage-statement-expression.cpp b/compiler-rt/test/profile/Linux/coverage-statement-expression.cpp new file mode 100644 index 0..5894275b941a2 --- /dev/null +++ b/compiler-rt/test/profile/Linux/coverage-statement-expression.cpp @@ -0,0 +1,19 @@ +// RUN: %clangxx_profgen -std=gnu++17 -fuse-ld=lld -fcoverage-mapping -o %t %s +// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t +// RUN: llvm-profdata merge -o %t.profdata %t.profraw +// RUN: llvm-cov show %t -instr-profile=%t.profdata 2>&1 | FileCheck %s + +#include + +__attribute__ ((__noreturn__)) +void foo(void) { while (1); } // CHECK: [[@LINE]]| 0|void foo(void) +_Noreturn void bar(void) { while (1); } // CHECK: [[@LINE]]| 0|_Noreturn void bar(void) +// CHECK: [[@LINE]]| | +int main(int argc, char **argv) { // CHECK: [[@LINE]]| 1|int main( + int rc = ({ if (argc > 3) foo(); 0; }); // CHECK: [[@LINE]]| 1| int rc = + printf("coverage after foo is present\n");// CHECK: [[@LINE]]| 1| printf( +// CHECK: [[@LINE]]| | + int rc2 = ({ if (argc > 3) bar(); 0; }); // CHECK: [[@LINE]]| 1| int rc2 = + printf("coverage after bar is present\n");// CHECK: [[@LINE]]| 1| printf( + return rc + rc2; // CHECK: [[@LINE]]| 1| return rc +} // CHECK: [[@LINE]]| 1|} >From 0dc7ea6a13b34901bb6ca0253ad73e8ef5037244 Mon Sep 17 00:00:00 2001 From: Justin Cady Date: Fri, 14 Mar 2025 12:32:57 -0400 Subject: [PATCH 2/3] Avoid format warning to preserve readable CHECK lines --- .../test/profile/Linux/coverage-statement-expression.cpp| 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler-rt/test/profile/Linux/coverage-statement-expression.cpp b/compiler-rt/test/profile/Linux/coverage-statement-expression.cpp index 5894275b941a2..7c76555e3300b 100644 --- a/compiler-rt/test/profile/Linux/coverage-statement-expression.cpp +++ b/compiler-rt/test/profile/Linux/coverage-statement-expression.cpp @@ -5,6 +5,7 @@ #include +// clang-f
[clang] [compiler-rt] [Coverage] Fix region termination for GNU statement expressions (PR #130976)
@@ -346,6 +346,12 @@ int elsecondnoret(void) { return 0; } +// CHECK-LABEL: _Z18statementexprnoretb +int statementexprnoret(bool crash) { + int rc = ({ if (crash) abort(); 0; }); // CHECK-NOT: Gap,File 0, [[@LINE]]:41 -> [[@LINE+1]]:3 = 0 justincady wrote: Thanks, I pushed a commit to fix this. https://github.com/llvm/llvm-project/pull/130976 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [compiler-rt] [Coverage] Fix region termination for GNU statement expressions (PR #130976)
justincady wrote: @MaskRay If you're satisfied with the current diff, could you please commit this whenever you get the chance? Thank you. https://github.com/llvm/llvm-project/pull/130976 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [compiler-rt] [Coverage] Fix region termination for GNU statement expressions (PR #130976)
https://github.com/justincady updated https://github.com/llvm/llvm-project/pull/130976 >From 1b7884bbff037efa5c69eeecafe8db282561b2fc Mon Sep 17 00:00:00 2001 From: Justin Cady Date: Wed, 12 Mar 2025 11:23:19 -0400 Subject: [PATCH] [Coverage] Fix region termination for GNU statement expressions Calls to __noreturn__ functions result in region termination for coverage mapping. But this creates incorrect coverage results when __noreturn__ functions (or other constructs that result in region termination) occur within [GNU statement expressions][1]. In this scenario an extra gap region is introduced within VisitStmt, such that if the following line does not introduce a new region it is unconditionally counted as uncovered. This change adjusts the mapping such that terminate statements within statement expressions do not propagate that termination state after the statement expression is processed. [1]: https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html Fixes #124296 --- clang/lib/CodeGen/CoverageMappingGen.cpp | 8 +++ .../CoverageMapping/terminate-statements.cpp | 7 +++ .../Linux/coverage-statement-expression.cpp | 21 +++ 3 files changed, 36 insertions(+) create mode 100644 compiler-rt/test/profile/Linux/coverage-statement-expression.cpp diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp index f09157771d2b5..73811d15979d5 100644 --- a/clang/lib/CodeGen/CoverageMappingGen.cpp +++ b/clang/lib/CodeGen/CoverageMappingGen.cpp @@ -1505,6 +1505,14 @@ struct CounterCoverageMappingBuilder handleFileExit(getEnd(S)); } + void VisitStmtExpr(const StmtExpr *E) { +Visit(E->getSubStmt()); +// Any region termination (such as a noreturn CallExpr) within the statement +// expression has been handled by visiting the sub-statement. The visitor +// cannot be at a terminate statement leaving the statement expression. +HasTerminateStmt = false; + } + void VisitDecl(const Decl *D) { Stmt *Body = D->getBody(); diff --git a/clang/test/CoverageMapping/terminate-statements.cpp b/clang/test/CoverageMapping/terminate-statements.cpp index 0067185fee8e6..3f8e43f0fbcb6 100644 --- a/clang/test/CoverageMapping/terminate-statements.cpp +++ b/clang/test/CoverageMapping/terminate-statements.cpp @@ -346,6 +346,12 @@ int elsecondnoret(void) { return 0; } +// CHECK-LABEL: _Z18statementexprnoretb +int statementexprnoret(bool crash) { + int rc = ({ if (crash) abort(); 0; }); // CHECK: File 0, 351:35 -> 352:12 = (#0 - #1) + return rc; // CHECK-NOT: Gap +} + int main() { foo(0); foo(1); @@ -368,5 +374,6 @@ int main() { ornoret(); abstractcondnoret(); elsecondnoret(); + statementexprnoret(false); return 0; } diff --git a/compiler-rt/test/profile/Linux/coverage-statement-expression.cpp b/compiler-rt/test/profile/Linux/coverage-statement-expression.cpp new file mode 100644 index 0..7c76555e3300b --- /dev/null +++ b/compiler-rt/test/profile/Linux/coverage-statement-expression.cpp @@ -0,0 +1,21 @@ +// RUN: %clangxx_profgen -std=gnu++17 -fuse-ld=lld -fcoverage-mapping -o %t %s +// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t +// RUN: llvm-profdata merge -o %t.profdata %t.profraw +// RUN: llvm-cov show %t -instr-profile=%t.profdata 2>&1 | FileCheck %s + +#include + +// clang-format off +__attribute__ ((__noreturn__)) +void foo(void) { while (1); } // CHECK: [[@LINE]]| 0|void foo(void) +_Noreturn void bar(void) { while (1); } // CHECK: [[@LINE]]| 0|_Noreturn void bar(void) +// CHECK: [[@LINE]]| | +int main(int argc, char **argv) { // CHECK: [[@LINE]]| 1|int main( + int rc = ({ if (argc > 3) foo(); 0; }); // CHECK: [[@LINE]]| 1| int rc = + printf("coverage after foo is present\n");// CHECK: [[@LINE]]| 1| printf( +// CHECK: [[@LINE]]| | + int rc2 = ({ if (argc > 3) bar(); 0; }); // CHECK: [[@LINE]]| 1| int rc2 = + printf("coverage after bar is present\n");// CHECK: [[@LINE]]| 1| printf( + return rc + rc2; // CHECK: [[@LINE]]| 1| return rc +} // CHECK: [[@LINE]]| 1|} +// clang-format on ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [compiler-rt] [Coverage] Fix region termination for GNU statement expressions (PR #130976)
https://github.com/justincady updated https://github.com/llvm/llvm-project/pull/130976 >From 422fefad20557f1d9777afa363f558c92564f0ee Mon Sep 17 00:00:00 2001 From: Justin Cady Date: Wed, 12 Mar 2025 11:23:19 -0400 Subject: [PATCH] [Coverage] Fix region termination for GNU statement expressions Calls to __noreturn__ functions result in region termination for coverage mapping. But this creates incorrect coverage results when __noreturn__ functions (or other constructs that result in region termination) occur within [GNU statement expressions][1]. In this scenario an extra gap region is introduced within VisitStmt, such that if the following line does not introduce a new region it is unconditionally counted as uncovered. This change adjusts the mapping such that terminate statements within statement expressions do not propagate that termination state after the statement expression is processed. [1]: https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html Fixes #124296 --- clang/lib/CodeGen/CoverageMappingGen.cpp | 8 +++ .../CoverageMapping/terminate-statements.cpp | 7 +++ .../Linux/coverage-statement-expression.cpp | 21 +++ 3 files changed, 36 insertions(+) create mode 100644 compiler-rt/test/profile/Linux/coverage-statement-expression.cpp diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp index f09157771d2b5..73811d15979d5 100644 --- a/clang/lib/CodeGen/CoverageMappingGen.cpp +++ b/clang/lib/CodeGen/CoverageMappingGen.cpp @@ -1505,6 +1505,14 @@ struct CounterCoverageMappingBuilder handleFileExit(getEnd(S)); } + void VisitStmtExpr(const StmtExpr *E) { +Visit(E->getSubStmt()); +// Any region termination (such as a noreturn CallExpr) within the statement +// expression has been handled by visiting the sub-statement. The visitor +// cannot be at a terminate statement leaving the statement expression. +HasTerminateStmt = false; + } + void VisitDecl(const Decl *D) { Stmt *Body = D->getBody(); diff --git a/clang/test/CoverageMapping/terminate-statements.cpp b/clang/test/CoverageMapping/terminate-statements.cpp index 0067185fee8e6..3f8e43f0fbcb6 100644 --- a/clang/test/CoverageMapping/terminate-statements.cpp +++ b/clang/test/CoverageMapping/terminate-statements.cpp @@ -346,6 +346,12 @@ int elsecondnoret(void) { return 0; } +// CHECK-LABEL: _Z18statementexprnoretb +int statementexprnoret(bool crash) { + int rc = ({ if (crash) abort(); 0; }); // CHECK: File 0, 351:35 -> 352:12 = (#0 - #1) + return rc; // CHECK-NOT: Gap +} + int main() { foo(0); foo(1); @@ -368,5 +374,6 @@ int main() { ornoret(); abstractcondnoret(); elsecondnoret(); + statementexprnoret(false); return 0; } diff --git a/compiler-rt/test/profile/Linux/coverage-statement-expression.cpp b/compiler-rt/test/profile/Linux/coverage-statement-expression.cpp new file mode 100644 index 0..7c76555e3300b --- /dev/null +++ b/compiler-rt/test/profile/Linux/coverage-statement-expression.cpp @@ -0,0 +1,21 @@ +// RUN: %clangxx_profgen -std=gnu++17 -fuse-ld=lld -fcoverage-mapping -o %t %s +// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t +// RUN: llvm-profdata merge -o %t.profdata %t.profraw +// RUN: llvm-cov show %t -instr-profile=%t.profdata 2>&1 | FileCheck %s + +#include + +// clang-format off +__attribute__ ((__noreturn__)) +void foo(void) { while (1); } // CHECK: [[@LINE]]| 0|void foo(void) +_Noreturn void bar(void) { while (1); } // CHECK: [[@LINE]]| 0|_Noreturn void bar(void) +// CHECK: [[@LINE]]| | +int main(int argc, char **argv) { // CHECK: [[@LINE]]| 1|int main( + int rc = ({ if (argc > 3) foo(); 0; }); // CHECK: [[@LINE]]| 1| int rc = + printf("coverage after foo is present\n");// CHECK: [[@LINE]]| 1| printf( +// CHECK: [[@LINE]]| | + int rc2 = ({ if (argc > 3) bar(); 0; }); // CHECK: [[@LINE]]| 1| int rc2 = + printf("coverage after bar is present\n");// CHECK: [[@LINE]]| 1| printf( + return rc + rc2; // CHECK: [[@LINE]]| 1| return rc +} // CHECK: [[@LINE]]| 1|} +// clang-format on ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [compiler-rt] Reland [Coverage] Fix region termination for GNU statement expressions (PR #132222)
justincady wrote: This is the buildbot failure from the initial commit: https://lab.llvm.org/buildbot/#/builders/133/builds/13131 I updated the failing test with the same restrictions as other tests using `-fuse-ld=lld` under `compiler-rt/test/profile/Linux`, specifically: ``` // REQUIRES: lld-available // XFAIL: powerpc64-target-arch ``` https://github.com/llvm/llvm-project/pull/13 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [compiler-rt] Reland [Coverage] Fix region termination for GNU statement expressions (PR #132222)
https://github.com/justincady created https://github.com/llvm/llvm-project/pull/13 Relands #130976 with adjustments to test requirements. Calls to __noreturn__ functions result in region termination for coverage mapping. But this creates incorrect coverage results when __noreturn__ functions (or other constructs that result in region termination) occur within [GNU statement expressions][1]. In this scenario an extra gap region is introduced within VisitStmt, such that if the following line does not introduce a new region it is unconditionally counted as uncovered. This change adjusts the mapping such that terminate statements within statement expressions do not propagate that termination state after the statement expression is processed. [1]: https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html Fixes #124296 >From e282d307482eb598238da387322dfdb1b0b46ed3 Mon Sep 17 00:00:00 2001 From: Justin Cady Date: Thu, 20 Mar 2025 10:01:42 -0400 Subject: [PATCH] Reland [Coverage] Fix region termination for GNU statement expressions Relands #130976 with adjustments to test requirements. Calls to __noreturn__ functions result in region termination for coverage mapping. But this creates incorrect coverage results when __noreturn__ functions (or other constructs that result in region termination) occur within [GNU statement expressions][1]. In this scenario an extra gap region is introduced within VisitStmt, such that if the following line does not introduce a new region it is unconditionally counted as uncovered. This change adjusts the mapping such that terminate statements within statement expressions do not propagate that termination state after the statement expression is processed. [1]: https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html Fixes #124296 --- clang/lib/CodeGen/CoverageMappingGen.cpp | 8 +++ .../CoverageMapping/terminate-statements.cpp | 7 ++ .../Linux/coverage-statement-expression.cpp | 24 +++ 3 files changed, 39 insertions(+) create mode 100644 compiler-rt/test/profile/Linux/coverage-statement-expression.cpp diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp index f09157771d2b5..73811d15979d5 100644 --- a/clang/lib/CodeGen/CoverageMappingGen.cpp +++ b/clang/lib/CodeGen/CoverageMappingGen.cpp @@ -1505,6 +1505,14 @@ struct CounterCoverageMappingBuilder handleFileExit(getEnd(S)); } + void VisitStmtExpr(const StmtExpr *E) { +Visit(E->getSubStmt()); +// Any region termination (such as a noreturn CallExpr) within the statement +// expression has been handled by visiting the sub-statement. The visitor +// cannot be at a terminate statement leaving the statement expression. +HasTerminateStmt = false; + } + void VisitDecl(const Decl *D) { Stmt *Body = D->getBody(); diff --git a/clang/test/CoverageMapping/terminate-statements.cpp b/clang/test/CoverageMapping/terminate-statements.cpp index 0067185fee8e6..3f8e43f0fbcb6 100644 --- a/clang/test/CoverageMapping/terminate-statements.cpp +++ b/clang/test/CoverageMapping/terminate-statements.cpp @@ -346,6 +346,12 @@ int elsecondnoret(void) { return 0; } +// CHECK-LABEL: _Z18statementexprnoretb +int statementexprnoret(bool crash) { + int rc = ({ if (crash) abort(); 0; }); // CHECK: File 0, 351:35 -> 352:12 = (#0 - #1) + return rc; // CHECK-NOT: Gap +} + int main() { foo(0); foo(1); @@ -368,5 +374,6 @@ int main() { ornoret(); abstractcondnoret(); elsecondnoret(); + statementexprnoret(false); return 0; } diff --git a/compiler-rt/test/profile/Linux/coverage-statement-expression.cpp b/compiler-rt/test/profile/Linux/coverage-statement-expression.cpp new file mode 100644 index 0..19300411d54a2 --- /dev/null +++ b/compiler-rt/test/profile/Linux/coverage-statement-expression.cpp @@ -0,0 +1,24 @@ +// REQUIRES: lld-available +// XFAIL: powerpc64-target-arch + +// RUN: %clangxx_profgen -std=gnu++17 -fuse-ld=lld -fcoverage-mapping -o %t %s +// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t +// RUN: llvm-profdata merge -o %t.profdata %t.profraw +// RUN: llvm-cov show %t -instr-profile=%t.profdata 2>&1 | FileCheck %s + +#include + +// clang-format off +__attribute__ ((__noreturn__)) +void foo(void) { while (1); } // CHECK: [[@LINE]]| 0|void foo(void) +_Noreturn void bar(void) { while (1); } // CHECK: [[@LINE]]| 0|_Noreturn void bar(void) +// CHECK: [[@LINE]]| | +int main(int argc, char **argv) { // CHECK: [[@LINE]]| 1|int main( + int rc = ({ if (argc > 3) foo(); 0; }); // CHECK: [[@LINE]]| 1| int rc = + printf("coverage after foo is present\n");// CHECK: [[@LINE]]| 1| printf( +// CHECK: [[@LINE]]| | + int rc2 = ({ if (argc > 3) bar(); 0; }); // CHECK: [[@LINE]]| 1| int rc2 = + printf("c
[clang] [compiler-rt] Revert "[Coverage] Fix region termination for GNU statement expressions" (PR #132095)
https://github.com/justincady closed https://github.com/llvm/llvm-project/pull/132095 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [compiler-rt] [Coverage] Fix region creation after try statements (PR #133463)
justincady wrote: Coverage report before: https://github.com/user-attachments/assets/80bb84a0-a76e-4f45-aca8-fd53378caa73"; /> Coverage report after: https://github.com/user-attachments/assets/987ae207-0eaf-4f33-aeb0-387c27cb382f"; /> https://github.com/llvm/llvm-project/pull/133463 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [compiler-rt] [Coverage] Fix region creation after try statements (PR #133463)
https://github.com/justincady created https://github.com/llvm/llvm-project/pull/133463 In cases where a terminating statement exists within the try or catch block the coverage mapping can be incorrect. Coverage reports display lines following the last catch block as uncovered, when the lines have been executed. This change adjusts the mapping such that an extra region is only created after a try block if the try itself contains the terminating statement. The testing validates coverage more broadly than the above to ensure other mapping around exception handling does not regress with this change. >From 6f79ddba80fa391a8c1ddbd3b2217f2e5a9ce21b Mon Sep 17 00:00:00 2001 From: Justin Cady Date: Fri, 28 Mar 2025 12:07:44 -0400 Subject: [PATCH] [Coverage] Fix region creation after try statements In cases where a terminating statement exists within the try or catch block the coverage mapping can be incorrect. Coverage reports display lines following the last catch block as uncovered, when the lines have been executed. This change adjusts the mapping such that an extra region is only created after a try block if the try itself contains the terminating statement. The testing validates coverage more broadly than the above to ensure other mapping around exception handling does not regress with this change. --- clang/lib/CodeGen/CoverageMappingGen.cpp | 10 +- clang/test/CoverageMapping/trycatch.cpp | 4 +- .../test/profile/Linux/coverage-exception.cpp | 142 ++ 3 files changed, 152 insertions(+), 4 deletions(-) create mode 100644 compiler-rt/test/profile/Linux/coverage-exception.cpp diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp index 73811d15979d5..f3b819bcf3b20 100644 --- a/clang/lib/CodeGen/CoverageMappingGen.cpp +++ b/clang/lib/CodeGen/CoverageMappingGen.cpp @@ -2123,11 +2123,17 @@ struct CounterCoverageMappingBuilder Counter ParentCount = getRegion().getCounter(); propagateCounts(ParentCount, S->getTryBlock()); +bool TryHasTerminateStmt = HasTerminateStmt; + for (unsigned I = 0, E = S->getNumHandlers(); I < E; ++I) Visit(S->getHandler(I)); -Counter ExitCount = getRegionCounter(S); -pushRegion(ExitCount); +if (TryHasTerminateStmt) { + Counter ExitCount = getRegionCounter(S); + pushRegion(ExitCount); +} + +HasTerminateStmt = TryHasTerminateStmt; } void VisitCXXCatchStmt(const CXXCatchStmt *S) { diff --git a/clang/test/CoverageMapping/trycatch.cpp b/clang/test/CoverageMapping/trycatch.cpp index 89fae8af9b720..e5d2482c6b151 100644 --- a/clang/test/CoverageMapping/trycatch.cpp +++ b/clang/test/CoverageMapping/trycatch.cpp @@ -33,5 +33,5 @@ int main() { // CHECK-NEXT: File 0, [[@LINE]]:12 -> [[@ catch(const Warning &w) { // CHECK-NEXT: File 0, [[@LINE]]:27 -> [[@LINE+2]]:4 = #4 j = 0; } - return 0; // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE]]:11 = #1 -} + return 0; // CHECK-NOT: File 0 +} // CHECK-NOT: File 0 diff --git a/compiler-rt/test/profile/Linux/coverage-exception.cpp b/compiler-rt/test/profile/Linux/coverage-exception.cpp new file mode 100644 index 0..c12303363fbb6 --- /dev/null +++ b/compiler-rt/test/profile/Linux/coverage-exception.cpp @@ -0,0 +1,142 @@ +// REQUIRES: lld-available +// XFAIL: powerpc64-target-arch + +// RUN: %clangxx_profgen -std=c++17 -fuse-ld=lld -fcoverage-mapping -o %t %s +// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t +// RUN: llvm-profdata merge -o %t.profdata %t.profraw +// RUN: llvm-cov show %t -instr-profile=%t.profdata 2>&1 | FileCheck %s + +#include +#include + +#define TRY_AND_CATCH_ALL(x) \ + try { \ +(x); \ + } catch (...) { \ + } + +#define TRY_MAYBE_CRASH(x) \ + try { \ +if ((x)) { \ + printf("no crash\n"); \ +} else { \ + abort(); \ +} \ + } catch (...) { \ + } + +#define TRY_AND_CATCH_CRASHES(x) \ + try { \ +(x);
[clang] [compiler-rt] [Coverage] Fix region termination for GNU statement expressions (PR #130976)
https://github.com/justincady updated https://github.com/llvm/llvm-project/pull/130976 >From 6f3557780d06d6a2b1a7f315c49a3ad533d821e5 Mon Sep 17 00:00:00 2001 From: Justin Cady Date: Wed, 12 Mar 2025 11:23:19 -0400 Subject: [PATCH 1/2] [Coverage] Fix region termination for GNU statement expressions Calls to __noreturn__ functions result in region termination for coverage mapping. But this creates incorrect coverage results when __noreturn__ functions (or other constructs that result in region termination) occur within [GNU statement expressions][1]. In this scenario an extra gap region is introduced within VisitStmt, such that if the following line does not introduce a new region it is unconditionally counted as uncovered. This change adjusts the mapping such that terminate statements within statement expressions do not propagate that termination state after the statement expression is processed. [1]: https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html Fixes #124296 --- clang/lib/CodeGen/CoverageMappingGen.cpp | 8 .../CoverageMapping/terminate-statements.cpp | 7 +++ .../Linux/coverage-statement-expression.cpp | 19 +++ 3 files changed, 34 insertions(+) create mode 100644 compiler-rt/test/profile/Linux/coverage-statement-expression.cpp diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp index f09157771d2b5..73811d15979d5 100644 --- a/clang/lib/CodeGen/CoverageMappingGen.cpp +++ b/clang/lib/CodeGen/CoverageMappingGen.cpp @@ -1505,6 +1505,14 @@ struct CounterCoverageMappingBuilder handleFileExit(getEnd(S)); } + void VisitStmtExpr(const StmtExpr *E) { +Visit(E->getSubStmt()); +// Any region termination (such as a noreturn CallExpr) within the statement +// expression has been handled by visiting the sub-statement. The visitor +// cannot be at a terminate statement leaving the statement expression. +HasTerminateStmt = false; + } + void VisitDecl(const Decl *D) { Stmt *Body = D->getBody(); diff --git a/clang/test/CoverageMapping/terminate-statements.cpp b/clang/test/CoverageMapping/terminate-statements.cpp index 0067185fee8e6..d03e35630b317 100644 --- a/clang/test/CoverageMapping/terminate-statements.cpp +++ b/clang/test/CoverageMapping/terminate-statements.cpp @@ -346,6 +346,12 @@ int elsecondnoret(void) { return 0; } +// CHECK-LABEL: _Z18statementexprnoretb +int statementexprnoret(bool crash) { + int rc = ({ if (crash) abort(); 0; }); // CHECK-NOT: Gap,File 0, [[@LINE]]:41 -> [[@LINE+1]]:3 = 0 + return rc; +} + int main() { foo(0); foo(1); @@ -368,5 +374,6 @@ int main() { ornoret(); abstractcondnoret(); elsecondnoret(); + statementexprnoret(false); return 0; } diff --git a/compiler-rt/test/profile/Linux/coverage-statement-expression.cpp b/compiler-rt/test/profile/Linux/coverage-statement-expression.cpp new file mode 100644 index 0..5894275b941a2 --- /dev/null +++ b/compiler-rt/test/profile/Linux/coverage-statement-expression.cpp @@ -0,0 +1,19 @@ +// RUN: %clangxx_profgen -std=gnu++17 -fuse-ld=lld -fcoverage-mapping -o %t %s +// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t +// RUN: llvm-profdata merge -o %t.profdata %t.profraw +// RUN: llvm-cov show %t -instr-profile=%t.profdata 2>&1 | FileCheck %s + +#include + +__attribute__ ((__noreturn__)) +void foo(void) { while (1); } // CHECK: [[@LINE]]| 0|void foo(void) +_Noreturn void bar(void) { while (1); } // CHECK: [[@LINE]]| 0|_Noreturn void bar(void) +// CHECK: [[@LINE]]| | +int main(int argc, char **argv) { // CHECK: [[@LINE]]| 1|int main( + int rc = ({ if (argc > 3) foo(); 0; }); // CHECK: [[@LINE]]| 1| int rc = + printf("coverage after foo is present\n");// CHECK: [[@LINE]]| 1| printf( +// CHECK: [[@LINE]]| | + int rc2 = ({ if (argc > 3) bar(); 0; }); // CHECK: [[@LINE]]| 1| int rc2 = + printf("coverage after bar is present\n");// CHECK: [[@LINE]]| 1| printf( + return rc + rc2; // CHECK: [[@LINE]]| 1| return rc +} // CHECK: [[@LINE]]| 1|} >From 0dc7ea6a13b34901bb6ca0253ad73e8ef5037244 Mon Sep 17 00:00:00 2001 From: Justin Cady Date: Fri, 14 Mar 2025 12:32:57 -0400 Subject: [PATCH 2/2] Avoid format warning to preserve readable CHECK lines --- .../test/profile/Linux/coverage-statement-expression.cpp| 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler-rt/test/profile/Linux/coverage-statement-expression.cpp b/compiler-rt/test/profile/Linux/coverage-statement-expression.cpp index 5894275b941a2..7c76555e3300b 100644 --- a/compiler-rt/test/profile/Linux/coverage-statement-expression.cpp +++ b/compiler-rt/test/profile/Linux/coverage-statement-expression.cpp @@ -5,6 +5,7 @@ #include +// clang-f
[clang] [compiler-rt] [Coverage] Fix region termination for GNU statement expressions (PR #130976)
https://github.com/justincady updated https://github.com/llvm/llvm-project/pull/130976 >From 6f3557780d06d6a2b1a7f315c49a3ad533d821e5 Mon Sep 17 00:00:00 2001 From: Justin Cady Date: Wed, 12 Mar 2025 11:23:19 -0400 Subject: [PATCH 1/2] [Coverage] Fix region termination for GNU statement expressions Calls to __noreturn__ functions result in region termination for coverage mapping. But this creates incorrect coverage results when __noreturn__ functions (or other constructs that result in region termination) occur within [GNU statement expressions][1]. In this scenario an extra gap region is introduced within VisitStmt, such that if the following line does not introduce a new region it is unconditionally counted as uncovered. This change adjusts the mapping such that terminate statements within statement expressions do not propagate that termination state after the statement expression is processed. [1]: https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html Fixes #124296 --- clang/lib/CodeGen/CoverageMappingGen.cpp | 8 .../CoverageMapping/terminate-statements.cpp | 7 +++ .../Linux/coverage-statement-expression.cpp | 19 +++ 3 files changed, 34 insertions(+) create mode 100644 compiler-rt/test/profile/Linux/coverage-statement-expression.cpp diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp index f09157771d2b5..73811d15979d5 100644 --- a/clang/lib/CodeGen/CoverageMappingGen.cpp +++ b/clang/lib/CodeGen/CoverageMappingGen.cpp @@ -1505,6 +1505,14 @@ struct CounterCoverageMappingBuilder handleFileExit(getEnd(S)); } + void VisitStmtExpr(const StmtExpr *E) { +Visit(E->getSubStmt()); +// Any region termination (such as a noreturn CallExpr) within the statement +// expression has been handled by visiting the sub-statement. The visitor +// cannot be at a terminate statement leaving the statement expression. +HasTerminateStmt = false; + } + void VisitDecl(const Decl *D) { Stmt *Body = D->getBody(); diff --git a/clang/test/CoverageMapping/terminate-statements.cpp b/clang/test/CoverageMapping/terminate-statements.cpp index 0067185fee8e6..d03e35630b317 100644 --- a/clang/test/CoverageMapping/terminate-statements.cpp +++ b/clang/test/CoverageMapping/terminate-statements.cpp @@ -346,6 +346,12 @@ int elsecondnoret(void) { return 0; } +// CHECK-LABEL: _Z18statementexprnoretb +int statementexprnoret(bool crash) { + int rc = ({ if (crash) abort(); 0; }); // CHECK-NOT: Gap,File 0, [[@LINE]]:41 -> [[@LINE+1]]:3 = 0 + return rc; +} + int main() { foo(0); foo(1); @@ -368,5 +374,6 @@ int main() { ornoret(); abstractcondnoret(); elsecondnoret(); + statementexprnoret(false); return 0; } diff --git a/compiler-rt/test/profile/Linux/coverage-statement-expression.cpp b/compiler-rt/test/profile/Linux/coverage-statement-expression.cpp new file mode 100644 index 0..5894275b941a2 --- /dev/null +++ b/compiler-rt/test/profile/Linux/coverage-statement-expression.cpp @@ -0,0 +1,19 @@ +// RUN: %clangxx_profgen -std=gnu++17 -fuse-ld=lld -fcoverage-mapping -o %t %s +// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t +// RUN: llvm-profdata merge -o %t.profdata %t.profraw +// RUN: llvm-cov show %t -instr-profile=%t.profdata 2>&1 | FileCheck %s + +#include + +__attribute__ ((__noreturn__)) +void foo(void) { while (1); } // CHECK: [[@LINE]]| 0|void foo(void) +_Noreturn void bar(void) { while (1); } // CHECK: [[@LINE]]| 0|_Noreturn void bar(void) +// CHECK: [[@LINE]]| | +int main(int argc, char **argv) { // CHECK: [[@LINE]]| 1|int main( + int rc = ({ if (argc > 3) foo(); 0; }); // CHECK: [[@LINE]]| 1| int rc = + printf("coverage after foo is present\n");// CHECK: [[@LINE]]| 1| printf( +// CHECK: [[@LINE]]| | + int rc2 = ({ if (argc > 3) bar(); 0; }); // CHECK: [[@LINE]]| 1| int rc2 = + printf("coverage after bar is present\n");// CHECK: [[@LINE]]| 1| printf( + return rc + rc2; // CHECK: [[@LINE]]| 1| return rc +} // CHECK: [[@LINE]]| 1|} >From 0dc7ea6a13b34901bb6ca0253ad73e8ef5037244 Mon Sep 17 00:00:00 2001 From: Justin Cady Date: Fri, 14 Mar 2025 12:32:57 -0400 Subject: [PATCH 2/2] Avoid format warning to preserve readable CHECK lines --- .../test/profile/Linux/coverage-statement-expression.cpp| 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler-rt/test/profile/Linux/coverage-statement-expression.cpp b/compiler-rt/test/profile/Linux/coverage-statement-expression.cpp index 5894275b941a2..7c76555e3300b 100644 --- a/compiler-rt/test/profile/Linux/coverage-statement-expression.cpp +++ b/compiler-rt/test/profile/Linux/coverage-statement-expression.cpp @@ -5,6 +5,7 @@ #include +// clang-f
[clang] [compiler-rt] [Coverage] Fix region termination for GNU statement expressions (PR #130976)
https://github.com/justincady created https://github.com/llvm/llvm-project/pull/130976 Calls to __noreturn__ functions result in region termination for coverage mapping. But this creates incorrect coverage results when __noreturn__ functions (or other constructs that result in region termination) occur within [GNU statement expressions][1]. In this scenario an extra gap region is introduced within VisitStmt, such that if the following line does not introduce a new region it is unconditionally counted as uncovered. This change adjusts the mapping such that terminate statements within statement expressions do not propagate that termination state after the statement expression is processed. [1]: https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html Fixes #124296 >From 6f3557780d06d6a2b1a7f315c49a3ad533d821e5 Mon Sep 17 00:00:00 2001 From: Justin Cady Date: Wed, 12 Mar 2025 11:23:19 -0400 Subject: [PATCH] [Coverage] Fix region termination for GNU statement expressions Calls to __noreturn__ functions result in region termination for coverage mapping. But this creates incorrect coverage results when __noreturn__ functions (or other constructs that result in region termination) occur within [GNU statement expressions][1]. In this scenario an extra gap region is introduced within VisitStmt, such that if the following line does not introduce a new region it is unconditionally counted as uncovered. This change adjusts the mapping such that terminate statements within statement expressions do not propagate that termination state after the statement expression is processed. [1]: https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html Fixes #124296 --- clang/lib/CodeGen/CoverageMappingGen.cpp | 8 .../CoverageMapping/terminate-statements.cpp | 7 +++ .../Linux/coverage-statement-expression.cpp | 19 +++ 3 files changed, 34 insertions(+) create mode 100644 compiler-rt/test/profile/Linux/coverage-statement-expression.cpp diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp index f09157771d2b5..73811d15979d5 100644 --- a/clang/lib/CodeGen/CoverageMappingGen.cpp +++ b/clang/lib/CodeGen/CoverageMappingGen.cpp @@ -1505,6 +1505,14 @@ struct CounterCoverageMappingBuilder handleFileExit(getEnd(S)); } + void VisitStmtExpr(const StmtExpr *E) { +Visit(E->getSubStmt()); +// Any region termination (such as a noreturn CallExpr) within the statement +// expression has been handled by visiting the sub-statement. The visitor +// cannot be at a terminate statement leaving the statement expression. +HasTerminateStmt = false; + } + void VisitDecl(const Decl *D) { Stmt *Body = D->getBody(); diff --git a/clang/test/CoverageMapping/terminate-statements.cpp b/clang/test/CoverageMapping/terminate-statements.cpp index 0067185fee8e6..d03e35630b317 100644 --- a/clang/test/CoverageMapping/terminate-statements.cpp +++ b/clang/test/CoverageMapping/terminate-statements.cpp @@ -346,6 +346,12 @@ int elsecondnoret(void) { return 0; } +// CHECK-LABEL: _Z18statementexprnoretb +int statementexprnoret(bool crash) { + int rc = ({ if (crash) abort(); 0; }); // CHECK-NOT: Gap,File 0, [[@LINE]]:41 -> [[@LINE+1]]:3 = 0 + return rc; +} + int main() { foo(0); foo(1); @@ -368,5 +374,6 @@ int main() { ornoret(); abstractcondnoret(); elsecondnoret(); + statementexprnoret(false); return 0; } diff --git a/compiler-rt/test/profile/Linux/coverage-statement-expression.cpp b/compiler-rt/test/profile/Linux/coverage-statement-expression.cpp new file mode 100644 index 0..5894275b941a2 --- /dev/null +++ b/compiler-rt/test/profile/Linux/coverage-statement-expression.cpp @@ -0,0 +1,19 @@ +// RUN: %clangxx_profgen -std=gnu++17 -fuse-ld=lld -fcoverage-mapping -o %t %s +// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t +// RUN: llvm-profdata merge -o %t.profdata %t.profraw +// RUN: llvm-cov show %t -instr-profile=%t.profdata 2>&1 | FileCheck %s + +#include + +__attribute__ ((__noreturn__)) +void foo(void) { while (1); } // CHECK: [[@LINE]]| 0|void foo(void) +_Noreturn void bar(void) { while (1); } // CHECK: [[@LINE]]| 0|_Noreturn void bar(void) +// CHECK: [[@LINE]]| | +int main(int argc, char **argv) { // CHECK: [[@LINE]]| 1|int main( + int rc = ({ if (argc > 3) foo(); 0; }); // CHECK: [[@LINE]]| 1| int rc = + printf("coverage after foo is present\n");// CHECK: [[@LINE]]| 1| printf( +// CHECK: [[@LINE]]| | + int rc2 = ({ if (argc > 3) bar(); 0; }); // CHECK: [[@LINE]]| 1| int rc2 = + printf("coverage after bar is present\n");// CHECK: [[@LINE]]| 1| printf( + return rc + rc2; // CHECK: [[@LINE]]| 1| return rc +} // CHECK: [[@LINE]]| 1|}
[clang] [lld] [llvm] Integrated Distributed ThinLTO (DTLTO): Initial support (PR #126654)
justincady wrote: I just want to double check my understanding. :) If I were to convert [this example](https://gist.github.com/MaskRay/24f4e2eed208b9d8b0a3752575a665d4#distributed-thinlto) to its functional equivalent in DTLTO, would it be: ``` clang -fuse-ld=lld -O2 -flto=thin -fthinlto-distributor=distributor_process a.c b.c c.c ``` Where: - `distributor_process` receives a JSON file specifying all intermediate jobs - If necessary I can use `-Xthinlto-distributor=` to pass extra arguments to `distributor_process` - Each job invokes `--thinlto-remote-opt-tool` (defaults to clang) - LLD waits for the jobs to complete and performs the final link Is that correct? https://github.com/llvm/llvm-project/pull/126654 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [compiler-rt] Reland [Coverage] Fix region termination for GNU statement expressions (PR #132222)
https://github.com/justincady updated https://github.com/llvm/llvm-project/pull/13 >From fa652581d03c962b61e7a350e0e9da0874e67109 Mon Sep 17 00:00:00 2001 From: Justin Cady Date: Thu, 20 Mar 2025 10:01:42 -0400 Subject: [PATCH] Reland [Coverage] Fix region termination for GNU statement expressions Relands #130976 with adjustments to test requirements. Calls to __noreturn__ functions result in region termination for coverage mapping. But this creates incorrect coverage results when __noreturn__ functions (or other constructs that result in region termination) occur within [GNU statement expressions][1]. In this scenario an extra gap region is introduced within VisitStmt, such that if the following line does not introduce a new region it is unconditionally counted as uncovered. This change adjusts the mapping such that terminate statements within statement expressions do not propagate that termination state after the statement expression is processed. [1]: https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html Fixes #124296 --- clang/lib/CodeGen/CoverageMappingGen.cpp | 8 +++ .../CoverageMapping/terminate-statements.cpp | 7 ++ .../Linux/coverage-statement-expression.cpp | 24 +++ 3 files changed, 39 insertions(+) create mode 100644 compiler-rt/test/profile/Linux/coverage-statement-expression.cpp diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp index f09157771d2b5..73811d15979d5 100644 --- a/clang/lib/CodeGen/CoverageMappingGen.cpp +++ b/clang/lib/CodeGen/CoverageMappingGen.cpp @@ -1505,6 +1505,14 @@ struct CounterCoverageMappingBuilder handleFileExit(getEnd(S)); } + void VisitStmtExpr(const StmtExpr *E) { +Visit(E->getSubStmt()); +// Any region termination (such as a noreturn CallExpr) within the statement +// expression has been handled by visiting the sub-statement. The visitor +// cannot be at a terminate statement leaving the statement expression. +HasTerminateStmt = false; + } + void VisitDecl(const Decl *D) { Stmt *Body = D->getBody(); diff --git a/clang/test/CoverageMapping/terminate-statements.cpp b/clang/test/CoverageMapping/terminate-statements.cpp index 0067185fee8e6..ef6b6fd82687d 100644 --- a/clang/test/CoverageMapping/terminate-statements.cpp +++ b/clang/test/CoverageMapping/terminate-statements.cpp @@ -346,6 +346,12 @@ int elsecondnoret(void) { return 0; } +// CHECK-LABEL: _Z18statementexprnoretb: +int statementexprnoret(bool crash) { + int rc = ({ if (crash) abort(); 0; }); // CHECK: File 0, 351:35 -> 352:12 = (#0 - #1) + return rc; // CHECK-NOT: Gap +} + int main() { foo(0); foo(1); @@ -368,5 +374,6 @@ int main() { ornoret(); abstractcondnoret(); elsecondnoret(); + statementexprnoret(false); return 0; } diff --git a/compiler-rt/test/profile/Linux/coverage-statement-expression.cpp b/compiler-rt/test/profile/Linux/coverage-statement-expression.cpp new file mode 100644 index 0..19300411d54a2 --- /dev/null +++ b/compiler-rt/test/profile/Linux/coverage-statement-expression.cpp @@ -0,0 +1,24 @@ +// REQUIRES: lld-available +// XFAIL: powerpc64-target-arch + +// RUN: %clangxx_profgen -std=gnu++17 -fuse-ld=lld -fcoverage-mapping -o %t %s +// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t +// RUN: llvm-profdata merge -o %t.profdata %t.profraw +// RUN: llvm-cov show %t -instr-profile=%t.profdata 2>&1 | FileCheck %s + +#include + +// clang-format off +__attribute__ ((__noreturn__)) +void foo(void) { while (1); } // CHECK: [[@LINE]]| 0|void foo(void) +_Noreturn void bar(void) { while (1); } // CHECK: [[@LINE]]| 0|_Noreturn void bar(void) +// CHECK: [[@LINE]]| | +int main(int argc, char **argv) { // CHECK: [[@LINE]]| 1|int main( + int rc = ({ if (argc > 3) foo(); 0; }); // CHECK: [[@LINE]]| 1| int rc = + printf("coverage after foo is present\n");// CHECK: [[@LINE]]| 1| printf( +// CHECK: [[@LINE]]| | + int rc2 = ({ if (argc > 3) bar(); 0; }); // CHECK: [[@LINE]]| 1| int rc2 = + printf("coverage after bar is present\n");// CHECK: [[@LINE]]| 1| printf( + return rc + rc2; // CHECK: [[@LINE]]| 1| return rc +} // CHECK: [[@LINE]]| 1|} +// clang-format on ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [compiler-rt] [Coverage] Fix mapping for do-while loops with terminating statements (PR #139777)
https://github.com/justincady created https://github.com/llvm/llvm-project/pull/139777 The current region mapping for do-while loops that contain statements such as break or continue results in inaccurate line coverage reports for the line following the loop. This change handles terminating statements the same way that other loop constructs do, correcting the region mapping for accurate reports. It also fixes a fragile test relying on exact line numbers. Fixes #139122 >From fff85d9cc74e2fbcbf1b2f9c94463070155decd8 Mon Sep 17 00:00:00 2001 From: Justin Cady Date: Tue, 13 May 2025 15:08:45 -0400 Subject: [PATCH] [Coverage] Fix mapping for do-while loops with terminating statements The current region mapping for do-while loops that contain statements such as break or continue results in inaccurate line coverage reports for the line following the loop. This change handles terminating statements the same way that other loop constructs do, correcting the region mapping for accurate reports. It also fixes a fragile test relying on exact line numbers. Fixes #139122 --- clang/lib/CodeGen/CoverageMappingGen.cpp | 5 ++--- .../CoverageMapping/terminate-statements.cpp | 13 +++- .../test/profile/Linux/coverage-do-while.c| 21 +++ 3 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 compiler-rt/test/profile/Linux/coverage-do-while.c diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp index 73811d15979d5..6170dc7f59107 100644 --- a/clang/lib/CodeGen/CoverageMappingGen.cpp +++ b/clang/lib/CodeGen/CoverageMappingGen.cpp @@ -1703,14 +1703,13 @@ struct CounterCoverageMappingBuilder if (!IsCounterEqual(OutCount, ParentCount)) { pushRegion(OutCount); GapRegionCounter = OutCount; + if (BodyHasTerminateStmt) +HasTerminateStmt = true; } // Create Branch Region around condition. if (!llvm::EnableSingleByteCoverage) createBranchRegion(S->getCond(), BodyCount, BranchCount.Skipped); - -if (BodyHasTerminateStmt) - HasTerminateStmt = true; } void VisitForStmt(const ForStmt *S) { diff --git a/clang/test/CoverageMapping/terminate-statements.cpp b/clang/test/CoverageMapping/terminate-statements.cpp index ef6b6fd82687d..93d655794ccf5 100644 --- a/clang/test/CoverageMapping/terminate-statements.cpp +++ b/clang/test/CoverageMapping/terminate-statements.cpp @@ -348,10 +348,20 @@ int elsecondnoret(void) { // CHECK-LABEL: _Z18statementexprnoretb: int statementexprnoret(bool crash) { - int rc = ({ if (crash) abort(); 0; }); // CHECK: File 0, 351:35 -> 352:12 = (#0 - #1) + int rc = ({ if (crash) abort(); 0; }); // CHECK: File 0, [[@LINE]]:35 -> [[@LINE+1]]:12 = (#0 - #1) return rc; // CHECK-NOT: Gap } +// CHECK-LABEL: _Z13do_with_breaki: +int do_with_break(int n) { + do { +if (n == 87) { + break; +} // CHECK: File 0, [[@LINE-2]]:18 -> [[@LINE]]:6 = #2 + } while (0); // CHECK: File 0, [[@LINE]]:12 -> [[@LINE]]:13 = ((#0 + #1) - #2) + return 0; // CHECK-NOT: Gap,File 0, [[@LINE-1]]:15 +} + int main() { foo(0); foo(1); @@ -375,5 +385,6 @@ int main() { abstractcondnoret(); elsecondnoret(); statementexprnoret(false); + do_with_break(0); return 0; } diff --git a/compiler-rt/test/profile/Linux/coverage-do-while.c b/compiler-rt/test/profile/Linux/coverage-do-while.c new file mode 100644 index 0..9e112cbc4c6a3 --- /dev/null +++ b/compiler-rt/test/profile/Linux/coverage-do-while.c @@ -0,0 +1,21 @@ +// REQUIRES: lld-available +// XFAIL: powerpc64-target-arch + +// RUN: %clangxx_profgen -fuse-ld=lld -fcoverage-mapping -o %t %s +// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t +// RUN: llvm-profdata merge -o %t.profdata %t.profraw +// RUN: llvm-cov show %t -instr-profile=%t.profdata 2>&1 | FileCheck %s + +#include + +// clang-format off +int main(int argc, char **argv) { // CHECK: [[@LINE]]| 1|int main( + do { // CHECK: [[@LINE]]| 1| do { +if (argc == 87) { // CHECK: [[@LINE]]| 1|if (argc + break;// CHECK: [[@LINE]]| 0| break +} // CHECK: [[@LINE]]| 0|} + } while (0); // CHECK: [[@LINE]]| 1| } while + printf("coverage after do is present\n"); // CHECK: [[@LINE]]| 1| printf( + return 0; // CHECK: [[@LINE]]| 1| return +} // CHECK: [[@LINE]]| 1|} +// clang-format on ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [compiler-rt] [Coverage] Fix mapping for do-while loops with terminating statements (PR #139777)
https://github.com/justincady ready_for_review https://github.com/llvm/llvm-project/pull/139777 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [compiler-rt] [Coverage] Fix mapping for do-while loops with terminating statements (PR #139777)
justincady wrote: Ping. :) https://github.com/llvm/llvm-project/pull/139777 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [compiler-rt] [Coverage] Fix mapping for do-while loops with terminating statements (PR #139777)
https://github.com/justincady updated https://github.com/llvm/llvm-project/pull/139777 >From be83c3207bf195aa7c6df1ce155402fde5911821 Mon Sep 17 00:00:00 2001 From: Justin Cady Date: Tue, 13 May 2025 15:08:45 -0400 Subject: [PATCH] [Coverage] Fix mapping for do-while loops with terminating statements The current region mapping for do-while loops that contain statements such as break or continue results in inaccurate line coverage reports for the line following the loop. This change handles terminating statements the same way that other loop constructs do, correcting the region mapping for accurate reports. It also fixes a fragile test relying on exact line numbers. Fixes #139122 --- clang/lib/CodeGen/CoverageMappingGen.cpp | 5 ++--- .../CoverageMapping/terminate-statements.cpp | 13 +++- .../test/profile/Linux/coverage-do-while.c| 21 +++ 3 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 compiler-rt/test/profile/Linux/coverage-do-while.c diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp index 73811d15979d5..6170dc7f59107 100644 --- a/clang/lib/CodeGen/CoverageMappingGen.cpp +++ b/clang/lib/CodeGen/CoverageMappingGen.cpp @@ -1703,14 +1703,13 @@ struct CounterCoverageMappingBuilder if (!IsCounterEqual(OutCount, ParentCount)) { pushRegion(OutCount); GapRegionCounter = OutCount; + if (BodyHasTerminateStmt) +HasTerminateStmt = true; } // Create Branch Region around condition. if (!llvm::EnableSingleByteCoverage) createBranchRegion(S->getCond(), BodyCount, BranchCount.Skipped); - -if (BodyHasTerminateStmt) - HasTerminateStmt = true; } void VisitForStmt(const ForStmt *S) { diff --git a/clang/test/CoverageMapping/terminate-statements.cpp b/clang/test/CoverageMapping/terminate-statements.cpp index ef6b6fd82687d..93d655794ccf5 100644 --- a/clang/test/CoverageMapping/terminate-statements.cpp +++ b/clang/test/CoverageMapping/terminate-statements.cpp @@ -348,10 +348,20 @@ int elsecondnoret(void) { // CHECK-LABEL: _Z18statementexprnoretb: int statementexprnoret(bool crash) { - int rc = ({ if (crash) abort(); 0; }); // CHECK: File 0, 351:35 -> 352:12 = (#0 - #1) + int rc = ({ if (crash) abort(); 0; }); // CHECK: File 0, [[@LINE]]:35 -> [[@LINE+1]]:12 = (#0 - #1) return rc; // CHECK-NOT: Gap } +// CHECK-LABEL: _Z13do_with_breaki: +int do_with_break(int n) { + do { +if (n == 87) { + break; +} // CHECK: File 0, [[@LINE-2]]:18 -> [[@LINE]]:6 = #2 + } while (0); // CHECK: File 0, [[@LINE]]:12 -> [[@LINE]]:13 = ((#0 + #1) - #2) + return 0; // CHECK-NOT: Gap,File 0, [[@LINE-1]]:15 +} + int main() { foo(0); foo(1); @@ -375,5 +385,6 @@ int main() { abstractcondnoret(); elsecondnoret(); statementexprnoret(false); + do_with_break(0); return 0; } diff --git a/compiler-rt/test/profile/Linux/coverage-do-while.c b/compiler-rt/test/profile/Linux/coverage-do-while.c new file mode 100644 index 0..9e112cbc4c6a3 --- /dev/null +++ b/compiler-rt/test/profile/Linux/coverage-do-while.c @@ -0,0 +1,21 @@ +// REQUIRES: lld-available +// XFAIL: powerpc64-target-arch + +// RUN: %clangxx_profgen -fuse-ld=lld -fcoverage-mapping -o %t %s +// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t +// RUN: llvm-profdata merge -o %t.profdata %t.profraw +// RUN: llvm-cov show %t -instr-profile=%t.profdata 2>&1 | FileCheck %s + +#include + +// clang-format off +int main(int argc, char **argv) { // CHECK: [[@LINE]]| 1|int main( + do { // CHECK: [[@LINE]]| 1| do { +if (argc == 87) { // CHECK: [[@LINE]]| 1|if (argc + break;// CHECK: [[@LINE]]| 0| break +} // CHECK: [[@LINE]]| 0|} + } while (0); // CHECK: [[@LINE]]| 1| } while + printf("coverage after do is present\n"); // CHECK: [[@LINE]]| 1| printf( + return 0; // CHECK: [[@LINE]]| 1| return +} // CHECK: [[@LINE]]| 1|} +// clang-format on ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [compiler-rt] [Coverage] Fix mapping for do-while loops with terminating statements (PR #139777)
https://github.com/justincady closed https://github.com/llvm/llvm-project/pull/139777 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits