From patchwork Wed Sep 2 19:08:33 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?q?J=C3=B8rgen_Kvalsvik?= X-Patchwork-Id: 142753 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 940434B9DB73 for ; Wed, 2 Sep 2026 19:09:28 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 940434B9DB73 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=lambda.is header.i=@lambda.is header.a=rsa-sha256 header.s=dkim2 header.b=CnuG7pi+ X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mx.kolabnow.com (mx.kolabnow.com [185.254.79.34]) by sourceware.org (Postfix) with ESMTPS id 33D154BA2E09 for ; Wed, 2 Sep 2026 19:08:48 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 33D154BA2E09 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=lambda.is Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=lambda.is ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 33D154BA2E09 Authentication-Results: sourceware.org; arc=none smtp.remote-ip=185.254.79.34 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1788376129; cv=none; b=BU/Zqhbv4mgt5RVEwAieuYU7zLyCVu8wNsA9cCR/nk/+Kt09rK0p7x6i83VCidlDcXc9SbEhkTC3WkJbmzim4s1jtWrwI5cEMasYNa0T0qaoaYu+FXiOjrj1wnnEI2HDGTTCPzyKsXZIzh0KWUL+VDw52Ani/y/q/1tnNBS8m3c= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1788376129; c=relaxed/simple; bh=hptkxWdO3yOpJbEza5RvNhLHLm7YDUu7J++7Ox34zzE=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=i5SgslYg5Ob6tecgXNyISRxJwRMBEZfKmAJ9P0SafjjqUvTuUHAvJKAuGT4cJNODtdhUEAePNdLD9JK26uprqiPGpE6HxU7RlJ5gSKWR/HkiarZUIea+gCDeDjkq14qbUh/uMf4taf0SbMGWTYJyUmg5OW7oo+MsJGgycsukfnA= ARC-Authentication-Results: i=1; sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=lambda.is header.i=@lambda.is header.a=rsa-sha256 header.s=dkim2 header.b=CnuG7pi+ DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 33D154BA2E09 Received: from kolabnow.com (unknown [10.17.5.252]) by mx.kolabnow.com (Postfix) with ESMTPS id B8E6830EC246; Wed, 2 Sep 2026 21:08:45 +0200 (CEST) Authentication-Results: kolabnow.com (amavis); dkim=pass reason="pass (just generated, assumed good)" header.d=lambda.is DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=lambda.is; h= content-transfer-encoding:mime-version:message-id:date:date :subject:subject:from:from; s=dkim2; t=1788376125; x=1789240126; bh=hptkxWdO3yOpJbEza5RvNhLHLm7YDUu7J++7Ox34zzE=; b=CnuG7pi+PkCO j4N1PZYyyDP+oJwCFse9+rV10kmMsv9VS3V4j9wcSkHys5T46H44euH2hxZNQAZN WRq/GZ1mVk9ETQDJUQPjH/afpkiNSeVS2LstB9Fvb/wHv9iJZBLIzwYDBC5QCP7m bbmaikOrsdeDuOM0h9UAkXZ7H/iZvZ6NcorceNx1oE6qUr4IxBvAhVcB/bY3s4HX uArIx5DlVwP3uciVzCvmGpLGgVTyAZRuS7+DT+5t48zd/dXxvSrewlWbBhnxDFMu DcVDVxw+CEeDTtnOvpjRGmy344B6CYGnJKG3Bhk9WovE7F+pkFjJnCR7tbqac0/t /zg7qT4Ucw== From: =?utf-8?q?J=C3=B8rgen_Kvalsvik?= To: gcc-patches@gcc.gnu.org Cc: hubicka@ucw.cz, josmyers@redhat.com, =?utf-8?q?J=C3=B8rgen_Kvalsvik?= Subject: [PATCH] Support nested #pragma GCC suppress_coverage Date: Wed, 2 Sep 2026 21:08:33 +0200 Message-ID: <20260902190833.750027-1-j@lambda.is> MIME-Version: 1.0 X-Spam-Status: No, score=-10.9 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, SH_BODYURI_REVERSE_CSS, SPF_HELO_PASS, SPF_PASS, TXREP, URIBL_CSS_A shortcircuit=no autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces~patchwork=sourceware.org@gcc.gnu.org The warning on nested suppressions was intended to be helpful, but there are just more good reasons to nest suppression than problems we would catch by warnings. An obvious example is custom asserts as macros, which could legitimately be used in code suppressed for other reasons. There's also recursive macro expansion or other preprocessing that effectively expands this: REQUIRE (pred1 && pred2, "msg"); into this: #pragma GCC suppress_coverage begin #pragma GCC suppress_coverage begin ... #pragma GCC suppress_coverage end #pragma GCC suppress_coverage end which I think should not trigger a warning. There is a tradeoff. We lose the ability to warn unbalanced begin/end in the middle somewhere, and coverage silently will be suppressed for every subsequent line. #pragma GCC suppress_coverage begin // everything suppressed from here ... #pragma GCC suppress_coverage begin ... #pragma GCC suppress_coverage end // not closed here as intended, coverage still suppressed Thankfully those cases should be rare and easy to trace as it's not hard to see from where the rest of the file is suppressed. gcc/c-family/ChangeLog: * c-pragma.cc (handle_pragma_suppress_coverage): Don't warn on nested begin. * c-pragma.h (suppress_coverage_begin): Change return type to void. gcc/ChangeLog: * profile.cc (suppress_coverage_begin): Always push new range, change return type. (suppress_coverage_end): Search for last unclosed item. gcc/testsuite/ChangeLog: * gcc.dg/pragma-suppress-coverage.c: Add test case for nested suppressions. * gcc.misc-tests/gcov-39.c: Likewise. --- gcc/c-family/c-pragma.cc | 7 ++-- gcc/c-family/c-pragma.h | 2 +- gcc/profile.cc | 33 ++++++++++--------- .../gcc.dg/pragma-suppress-coverage.c | 18 ++++++++-- gcc/testsuite/gcc.misc-tests/gcov-39.c | 14 ++++++++ 5 files changed, 50 insertions(+), 24 deletions(-) diff --git a/gcc/c-family/c-pragma.cc b/gcc/c-family/c-pragma.cc index d0d4ff69fd7..38fd14ad808 100644 --- a/gcc/c-family/c-pragma.cc +++ b/gcc/c-family/c-pragma.cc @@ -1069,11 +1069,8 @@ handle_pragma_suppress_coverage (cpp_reader*) GCC_BAD ("no matching begin for %<#pragma GCC suppress_coverage end%>"); } else - { - if (!suppress_coverage_begin (input_location)) - GCC_BAD ("%<#pragma GCC suppress_coverage begin%> " - "was already in effect, ignored"); - } + suppress_coverage_begin (input_location); + if (pragma_lex (&x, &loc) != CPP_EOF) GCC_BAD_AT (loc, "junk at end of %<#pragma GCC suppress_coverage%>"); } diff --git a/gcc/c-family/c-pragma.h b/gcc/c-family/c-pragma.h index 5d28cb45c66..5428e476ba9 100644 --- a/gcc/c-family/c-pragma.h +++ b/gcc/c-family/c-pragma.h @@ -304,7 +304,7 @@ extern void c_pp_lookup_pragma (unsigned int, const char **, const char **); extern GTY(()) tree pragma_extern_prefix; /* For recording #pragma GCC suppress_coverage locations. */ -extern bool suppress_coverage_begin (location_t); +extern void suppress_coverage_begin (location_t); extern bool suppress_coverage_end (location_t); #endif /* GCC_C_PRAGMA_H */ diff --git a/gcc/profile.cc b/gcc/profile.cc index 52704e93866..d6fd22eaade 100644 --- a/gcc/profile.cc +++ b/gcc/profile.cc @@ -1247,32 +1247,35 @@ any_block_coverage_suppressed_p () UNKNOWN_LOCATION. */ static vec suppress_coverage_ranges; -/* Try to add LOC as the beginning of a new range. If a range was started - already, this is a no-op. Returns true if a new range was created. */ -bool +/* Try to add LOC as the beginning of a new range. A new range is always + created, even if the previous one was left open. */ +void suppress_coverage_begin (location_t loc) { - if (!suppress_coverage_ranges.is_empty () - && suppress_coverage_ranges.last ().m_finish == UNKNOWN_LOCATION) - return false; - loc = get_pure_location (expansion_point_location (loc)); source_range range = source_range::from_locations (loc, UNKNOWN_LOCATION); suppress_coverage_ranges.safe_push (range); - return true; } -/* Try to close the last range created by suppress_coverage_begin at LOC. If - the range has been closed already (or not opened), this is a no-op. Returns - true if a range was closed. */ +/* Try to close the last open range created by suppress_coverage_begin at LOC. + If all ranges have been closed already (or never opened), this is a no-op. + Returns true if a range was closed. */ bool suppress_coverage_end (location_t loc) { - if (suppress_coverage_ranges.is_empty () - || suppress_coverage_ranges.last ().m_finish != UNKNOWN_LOCATION) - return false; + if (suppress_coverage_ranges.is_empty ()) + return false; + + source_range *current = nullptr; + for (int i = suppress_coverage_ranges.length () - 1; !current && i >= 0; i--) + if (suppress_coverage_ranges[i].m_finish == UNKNOWN_LOCATION) + current = &suppress_coverage_ranges[i]; + + if (!current) + return false; + loc = get_pure_location (expansion_point_location (loc)); - suppress_coverage_ranges.last ().m_finish = loc; + current->m_finish = loc; return true; } diff --git a/gcc/testsuite/gcc.dg/pragma-suppress-coverage.c b/gcc/testsuite/gcc.dg/pragma-suppress-coverage.c index 2a3bc42e883..6f8de76a254 100644 --- a/gcc/testsuite/gcc.dg/pragma-suppress-coverage.c +++ b/gcc/testsuite/gcc.dg/pragma-suppress-coverage.c @@ -24,9 +24,21 @@ ^~~~ { dg-end-multiline-output "" } */ -#pragma GCC suppress_coverage begin -/* { dg-warning "'#pragma GCC suppress_coverage begin' was already in effect, ignored" "" { target *-*-* } .-1 } +/* Pushing multiple suppresions is fine, this works like a stack. It should + not trigger a warning because this could easily happen with recursive + expansions, for example when some assert-like macro with internal suppression + is used in a suppressed context. */ +#define suppress_push() _Pragma("GCC suppress_coverage begin") +#define suppress_pop() _Pragma("GCC suppress_coverage end") + +suppress_push() +suppress_pop() + +#pragma GCC suppress_coverage end + +#pragma GCC suppress_coverage end +/* { dg-warning "no matching begin for '#pragma GCC suppress_coverage end'" "" { target *-*-* } .-1 } { dg-begin-multiline-output "" } - #pragma GCC suppress_coverage begin + #pragma GCC suppress_coverage end ^~~ { dg-end-multiline-output "" } */ diff --git a/gcc/testsuite/gcc.misc-tests/gcov-39.c b/gcc/testsuite/gcc.misc-tests/gcov-39.c index 1847db8e89c..c1c9b35c88a 100644 --- a/gcc/testsuite/gcc.misc-tests/gcov-39.c +++ b/gcc/testsuite/gcc.misc-tests/gcov-39.c @@ -226,6 +226,19 @@ pathcov004d (int a, int b, int c, int d) } } +/* BEGIN paths + summary: 1/1 */ +int +nested001a (int a) { +/* END */ +#pragma GCC suppress_coverage begin + REQUIRE (a >= 0); + int suppressed_twice = a + a; + ENSURE (suppressed_twice > a); +#pragma GCC suppress_coverage end + return suppressed_twice; +} + int main () { @@ -238,6 +251,7 @@ main () suppressed_in_loop3 (10); pathcov004c (0, 0, 0, 0); pathcov004d (0, 1, 0, 0); + nested001a (1); } /* { dg-final { run-gcov prime-paths { --prime-paths-lines=both gcov-39.c } } } */