[clang] [Clang] Wide delimiters ('{{{') for expect strings (PR #77326)

via cfe-commits cfe-commits at lists.llvm.org
Tue Jan 9 07:46:27 PST 2024


https://github.com/sethp updated https://github.com/llvm/llvm-project/pull/77326

>From cd0b9aed2d9e53f9b38aaa0f73336acae06bfbee Mon Sep 17 00:00:00 2001
From: Seth Pellegrino <seth at codecopse.net>
Date: Sat, 6 Jan 2024 07:54:31 -0800
Subject: [PATCH 1/4] [Clang] Wide delimiters ('{{{') for expect strings

Prior to this commit, it was impossible to use the simple string
matching directives to look for most content that contains `{{`, such
as:

```
// expected-note {{my_struct{{1}, 2}}}
```

Which would parse like so:

```
             "nested" brace v
// expected-note {{my_struct{{1}, 2}}}
          closes the nested brace  ^ |
                            trailing }
```

And the frontend would complain 'cannot find end ('}}') of expected'.

At this snapshot, VerifyDiagnosticConsumer's parser now counts the
opening braces and looks for a matching length of closing sigils,
allowing the above to be written as:

```
// expected-note {{{my_struct{{1}, 2}}}}
   opening brace |-|                 |-|
  closing brace is '}}}', found here ^
```
---
 .../clang/Basic/DiagnosticFrontendKinds.td        |  2 +-
 clang/lib/Frontend/VerifyDiagnosticConsumer.cpp   | 15 +++++++++++----
 2 files changed, 12 insertions(+), 5 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
index 715e0c0dc8fa84..4bf0ab54a046c1 100644
--- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -166,7 +166,7 @@ def err_verify_no_such_marker : Error<
 def err_verify_missing_start : Error<
     "cannot find start ('{{') of expected %0">;
 def err_verify_missing_end : Error<
-    "cannot find end ('}}') of expected %0">;
+    "cannot find end ('%1') of expected %0">;
 def err_verify_invalid_content : Error<
     "invalid expected %0: %1">;
 def err_verify_missing_regex : Error<
diff --git a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
index ab8174f4f4db92..5eab7bd3619f19 100644
--- a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
+++ b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
@@ -612,12 +612,19 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
                    diag::err_verify_missing_start) << KindStr;
       continue;
     }
+    llvm::SmallString<8> CloseBrace("}}");
+    const char *const DelimBegin = PH.C;
     PH.Advance();
+    // Count the number of opening braces for `string` kinds
+    for (; !D.RegexKind && PH.Next("{"); PH.Advance())
+      CloseBrace += '}';
     const char* const ContentBegin = PH.C; // mark content begin
-    // Search for token: }}
-    if (!PH.SearchClosingBrace("{{", "}}")) {
-      Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
-                   diag::err_verify_missing_end) << KindStr;
+    // Search for closing brace
+    StringRef OpenBrace(DelimBegin, ContentBegin - DelimBegin);
+    if (!PH.SearchClosingBrace(OpenBrace, CloseBrace)) {
+      Diags.Report(Pos.getLocWithOffset(PH.C - PH.Begin),
+                   diag::err_verify_missing_end)
+          << KindStr << CloseBrace;
       continue;
     }
     const char* const ContentEnd = PH.P; // mark content end

>From 4922ee24a26da88dab73d55b59f8aa53c3077f13 Mon Sep 17 00:00:00 2001
From: Seth Pellegrino <seth at codecopse.net>
Date: Mon, 8 Jan 2024 09:04:41 -0800
Subject: [PATCH 2/4] fixup!: update docs

---
 clang/docs/InternalsManual.rst | 35 ++++++++++++++++++++++++++++++++--
 1 file changed, 33 insertions(+), 2 deletions(-)

diff --git a/clang/docs/InternalsManual.rst b/clang/docs/InternalsManual.rst
index 05fadf5a034464..d98f228fdf2c7b 100644
--- a/clang/docs/InternalsManual.rst
+++ b/clang/docs/InternalsManual.rst
@@ -3364,7 +3364,7 @@ Multiple occurrences accumulate prefixes.  For example,
 
 Specifying Diagnostics
 ^^^^^^^^^^^^^^^^^^^^^^
-Indicating that a line expects an error or a warning is simple. Put a comment
+Indicating that a line expects an error or a warning is easy. Put a comment
 on the line that has the diagnostic, use
 ``expected-{error,warning,remark,note}`` to tag if it's an expected error,
 warning, remark, or note (respectively), and place the expected text between
@@ -3373,6 +3373,9 @@ enough to ensure that the correct diagnostic was emitted. (Note: full text
 should be included in test cases unless there is a compelling reason to use
 truncated text instead.)
 
+For a full description of the matching behavior, including more complex
+matching scenarios, see :ref:`matching <DiagnosticMatching>` below.
+
 Here's an example of the most commonly used way to specify expected
 diagnostics:
 
@@ -3458,8 +3461,34 @@ A range can also be specified by ``<n>-<m>``. For example:
 
 In this example, the diagnostic may appear only once, if at all.
 
+.. _DiagnosticMatching:
+
+Matching Modes
+~~~~~~~~~~~~~~
+
+The default matching mode is simple string, which looks for the expected text
+that appears between the first `{{` and `}}` pair of the comment. The string is
+interpreted just as-is, with one exception: the sequence `\n` is converted to a
+single newline character. This mode matches the emitted diagnostic when the
+text appears as a substring at any position of the emitted message.
+
+To enable matching against desired strings that contain `}}` or `{{`, the
+string-mode parser accepts opening delimiters of more than two curly braces,
+like `{{{`. It then looks for a closing delimiter of equal "width" (i.e `}}}`).
+For example:
+
+.. code-block:: c++
+
+  // expected-note {{{evaluates to '{{2, 3, 4}} == {0, 3, 4}'}}}
+
+If your expected text contains `{{{` (three braces), then it may be delimited
+with `{{{{` (four braces), and so on. If your expected text contains enough
+repeated `{`s to fill up a `ptrdiff_t`, then you'll definitely crash the
+parser, possibly even as late as the delimiter handling.
+
 Regex matching mode may be selected by appending ``-re`` to the diagnostic type
-and including regexes wrapped in double curly braces in the directive, such as:
+and including regexes wrapped in double curly braces (`{{` and `}}`) in the
+directive, such as:
 
 .. code-block:: text
 
@@ -3471,6 +3500,8 @@ Examples matching error: "variable has incomplete type 'struct s'"
 
   // expected-error {{variable has incomplete type 'struct s'}}
   // expected-error {{variable has incomplete type}}
+  // expected-error {{{variable has incomplete type}}}
+  // expected-error {{{{variable has incomplete type}}}}
 
   // expected-error-re {{variable has type 'struct {{.}}'}}
   // expected-error-re {{variable has type 'struct {{.*}}'}}

>From 38ca2d630f3b53aed3a54856e48546b865c42ac2 Mon Sep 17 00:00:00 2001
From: Seth Pellegrino <seth at codecopse.net>
Date: Mon, 8 Jan 2024 10:39:13 -0800
Subject: [PATCH 3/4] fixup!: add test

---
 clang/test/Frontend/verify.c | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/clang/test/Frontend/verify.c b/clang/test/Frontend/verify.c
index 221b715c19e416..c549011d7b7a9a 100644
--- a/clang/test/Frontend/verify.c
+++ b/clang/test/Frontend/verify.c
@@ -157,3 +157,33 @@ unexpected b; // expected-error at 33 1-1 {{unknown type}}
 // what-error {{huh?}}
 // CHECK9: error: 'what-error' diagnostics expected but not seen:
 #endif
+
+#ifdef TEST_WIDE_DELIM
+// RUN: not %clang_cc1 -DTEST_WIDE_DELIM -verify %s 2>&1 | FileCheck -check-prefix=CHECK-WIDE-DELIM %s
+
+// expected-error {{{some message with {{}} in it}}}
+// expected-error {{{some message with  {}} in it}}}
+// expected-error {{{some message with {{}  in it}}}
+
+// expected-error-re {{{some {{.*}} regex with double braces}}}
+// expected-error-re {{{some message with {{}  in it}}}
+
+// expected-error {{{mismatched delim}}
+// expected-error-re {{{mismatched re {{.*} }}}
+// expected-error-re {{{no regex}}}
+
+#if 0
+//      CHECK-WIDE-DELIM: error: 'expected-error' diagnostics expected but not seen:
+// CHECK-WIDE-DELIM-NEXT:   verify.c Line 164: some message with {{[{]{}[}]}} in it
+// CHECK-WIDE-DELIM-NEXT:   verify.c Line 165: some message with  {}} in it
+// CHECK-WIDE-DELIM-NEXT:   verify.c Line 166: some message with {{[{]{[}]}}  in it
+// CHECK-WIDE-DELIM-NEXT:   verify.c Line 168: {some {{.*}} regex with double braces
+// CHECK-WIDE-DELIM-NEXT: error: 'expected-error' diagnostics seen but not expected:
+// CHECK-WIDE-DELIM-NEXT:   verify.c Line 169: cannot find end ('}}') of expected regex
+// CHECK-WIDE-DELIM-NEXT:   verify.c Line 171: cannot find end ('}}}') of expected string
+// CHECK-WIDE-DELIM-NEXT:   verify.c Line 172: cannot find end ('}}') of expected regex
+// CHECK-WIDE-DELIM-NEXT:   verify.c Line 173: cannot find start of regex ('{{[{][{]}}') in {no regex
+// CHECK-WIDE-DELIM-NEXT: 8 errors generated.
+#endif
+
+#endif

>From 019a8e0c598c32eb00d656bc4fbc3d740da6efb0 Mon Sep 17 00:00:00 2001
From: sethp <seth.pellegrino at gmail.com>
Date: Tue, 9 Jan 2024 07:46:19 -0800
Subject: [PATCH 4/4] fixup!: Update clang/docs/InternalsManual.rst

Review feedback
---
 clang/docs/InternalsManual.rst | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/clang/docs/InternalsManual.rst b/clang/docs/InternalsManual.rst
index d98f228fdf2c7b..a866f621c1003b 100644
--- a/clang/docs/InternalsManual.rst
+++ b/clang/docs/InternalsManual.rst
@@ -3481,10 +3481,9 @@ For example:
 
   // expected-note {{{evaluates to '{{2, 3, 4}} == {0, 3, 4}'}}}
 
-If your expected text contains `{{{` (three braces), then it may be delimited
-with `{{{{` (four braces), and so on. If your expected text contains enough
-repeated `{`s to fill up a `ptrdiff_t`, then you'll definitely crash the
-parser, possibly even as late as the delimiter handling.
+The intent is to allow the delimeter to be wider than the longest `{` or `}`
+brace sequence in the content, so that if your expected text contains `{{{`
+(three braces) it may be delimited with `{{{{` (four braces), and so on.
 
 Regex matching mode may be selected by appending ``-re`` to the diagnostic type
 and including regexes wrapped in double curly braces (`{{` and `}}`) in the



More information about the cfe-commits mailing list