@@ -283,6 +283,7 @@ diagnostic_context::initialize (int n_opts)
m_diagnostic_groups.m_group_nesting_depth = 0;
m_diagnostic_groups.m_diagnostic_nesting_level = 0;
m_diagnostic_groups.m_emission_count = 0;
+ m_diagnostic_groups.m_inhibiting_notes_from = 0;
m_output_sinks.safe_push
(new diagnostic_text_output_format (*this, nullptr, true));
m_set_locations_cb = nullptr;
@@ -891,6 +892,7 @@ diagnostic_context::check_max_errors (bool flush)
/* Take any action which is expected to happen after the diagnostic
is written out. This function does not always return. */
+
void
diagnostic_context::action_after_output (diagnostic_t diag_kind)
{
@@ -965,6 +967,50 @@ diagnostic_context::action_after_output (diagnostic_t diag_kind)
}
}
+/* State whether we should inhibit notes in the current diagnostic_group and
+ its future children if any. */
+
+void
+diagnostic_context::inhibit_notes_in_group (bool inhibit)
+{
+ int curr_depth = (m_diagnostic_groups.m_group_nesting_depth
+ + m_diagnostic_groups.m_diagnostic_nesting_level);
+
+ if (inhibit)
+ {
+ /* If we're already inhibiting, there's nothing to do. */
+ if (m_diagnostic_groups.m_inhibiting_notes_from)
+ return;
+
+ /* Since we're called via warning/error/... that all have their own
+ diagnostic_group, we must consider that we started inhibiting in their
+ parent. */
+ gcc_assert (m_diagnostic_groups.m_group_nesting_depth > 0);
+ m_diagnostic_groups.m_inhibiting_notes_from = curr_depth - 1;
+ }
+ else if (m_diagnostic_groups.m_inhibiting_notes_from)
+ {
+ /* Only cancel inhibition at the depth that set it up. */
+ if (curr_depth >= m_diagnostic_groups.m_inhibiting_notes_from)
+ return;
+
+ m_diagnostic_groups.m_inhibiting_notes_from = 0;
+ }
+}
+
+/* Return whether notes must be inhibited in the current diagnostic_group. */
+
+bool
+diagnostic_context::notes_inhibited_in_group () const
+{
+ if (m_diagnostic_groups.m_inhibiting_notes_from
+ && (m_diagnostic_groups.m_group_nesting_depth
+ + m_diagnostic_groups.m_diagnostic_nesting_level
+ >= m_diagnostic_groups.m_inhibiting_notes_from))
+ return true;
+ return false;
+}
+
/* class logical_location. */
/* Return true iff this is a function or method. */
@@ -1355,7 +1401,10 @@ diagnostic_context::report_diagnostic (diagnostic_info *diagnostic)
bool was_warning = (diagnostic->kind == DK_WARNING
|| diagnostic->kind == DK_PEDWARN);
if (was_warning && m_inhibit_warnings)
- return false;
+ {
+ inhibit_notes_in_group ();
+ return false;
+ }
if (m_adjust_diagnostic_info)
m_adjust_diagnostic_info (this, diagnostic);
@@ -1397,7 +1446,10 @@ diagnostic_context::report_diagnostic (diagnostic_info *diagnostic)
not disabled by #pragma GCC diagnostic anywhere along the inlining
stack. . */
if (!diagnostic_enabled (diagnostic))
- return false;
+ {
+ inhibit_notes_in_group ();
+ return false;
+ }
if ((was_warning || diagnostic->kind == DK_WARNING)
&& ((!m_warn_system_headers
@@ -1407,9 +1459,16 @@ diagnostic_context::report_diagnostic (diagnostic_info *diagnostic)
inlining stack (if there is one) are in system headers. */
return false;
+ if (diagnostic->kind == DK_NOTE && notes_inhibited_in_group ())
+ /* Bail for all the notes in the diagnostic_group that started to inhibit notes. */
+ return false;
+
if (diagnostic->kind != DK_NOTE && diagnostic->kind != DK_ICE)
check_max_errors (false);
+ /* We are accepting the diagnostic, so should stop inhibiting notes. */
+ inhibit_notes_in_group (/*inhibit=*/false);
+
m_lock++;
if (diagnostic->kind == DK_ICE || diagnostic->kind == DK_ICE_NOBT)
@@ -1743,6 +1802,8 @@ diagnostic_context::end_group ()
sink->on_end_group ();
m_diagnostic_groups.m_emission_count = 0;
}
+ /* We're popping one level, so might need to stop inhibiting notes. */
+ inhibit_notes_in_group (/*inhibit=*/false);
}
void
@@ -1755,6 +1816,8 @@ void
diagnostic_context::pop_nesting_level ()
{
--m_diagnostic_groups.m_diagnostic_nesting_level;
+ /* We're popping one level, so might need to stop inhibiting notes. */
+ inhibit_notes_in_group (/*inhibit=*/false);
}
void
@@ -950,8 +950,14 @@ private:
/* How many diagnostics have been emitted since the bottommost
diagnostic_group was pushed. */
int m_emission_count;
+
+ /* The "group+diagnostic" nesting depth from which to inhibit notes. */
+ int m_inhibiting_notes_from;
} m_diagnostic_groups;
+ void inhibit_notes_in_group (bool inhibit = true);
+ bool notes_inhibited_in_group () const;
+
/* The various sinks to which diagnostics are to be outputted
(text vs structured formats such as SARIF).
The sinks are owned by the context; this would be a
@@ -409,7 +409,10 @@ diagnostic subsystem that all diagnostics issued within the lifetime
of the @code{auto_diagnostic_group} are related. For example,
@option{-fdiagnostics-format=json} will treat the first diagnostic
emitted within the group as a top-level diagnostic, and all subsequent
-diagnostics within the group as its children.
+diagnostics within the group as its children. Also, if a warning in the
+group is inhibited at nesting depth D, all subsequent notes at that depth
+or deeper will be inhibited as well, until an error or another warning
+is emitted, the depth decreases below D, or the group is popped.
@subsection Quoting
Text should be quoted by either using the @samp{q} modifier in a directive
new file mode 100644
@@ -0,0 +1,7 @@
+// PR c++/118163
+// { dg-do "compile" }
+
+template<class T>
+struct S { // { dg-note "until the closing brace" }
+ S s; // { dg-error "has incomplete type" }
+};
new file mode 100644
@@ -0,0 +1,13 @@
+// PR c++/118163
+// { dg-do "compile" }
+// { dg-additional-options "-Wno-template-body" }
+
+template<class T>
+struct S { // { dg-bogus "until the closing brace" }
+ S s; // { dg-bogus "has incomplete type" }
+};
+
+// Check that we don't suppress errors outside of the body.
+struct forward_decl; // { dg-note "forward declaration" }
+template<class T>
+void foo (forward_decl) {} // { dg-error "has incomplete type" }
new file mode 100644
@@ -0,0 +1,15 @@
+// PR c++/118392
+// { dg-do "compile" }
+// { dg-additional-options "-w" }
+
+// Fake dg-note to make sure that notes are not pruned and we can use dg-bogus.
+// { dg-note "fake" "" { xfail *-*-* } }
+
+namespace xxx {
+ struct foo {
+ friend void bar(); // { dg-bogus "only here as a friend" }
+ };
+}
+void xxx::bar () {}
+
+void foo () {}