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

via cfe-commits cfe-commits at lists.llvm.org
Tue Jan 9 08:02:14 PST 2024


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

>From 1afdcda3bbf695430111873a69631a07e64ff610 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] [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/docs/InternalsManual.rst                | 34 +++++++++++++++++--
 .../clang/Basic/DiagnosticFrontendKinds.td    |  2 +-
 .../lib/Frontend/VerifyDiagnosticConsumer.cpp | 15 +++++---
 clang/test/Frontend/verify.c                  | 30 ++++++++++++++++
 4 files changed, 74 insertions(+), 7 deletions(-)

diff --git a/clang/docs/InternalsManual.rst b/clang/docs/InternalsManual.rst
index 05fadf5a034464..a866f621c1003b 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,33 @@ 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}'}}}
+
+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 in the directive, such as:
+and including regexes wrapped in double curly braces (`{{` and `}}`) in the
+directive, such as:
 
 .. code-block:: text
 
@@ -3471,6 +3499,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 {{.*}}'}}
diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
index 568000106a84dc..85ecfdf9de62d4 100644
--- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -167,7 +167,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 8a3d2286cd168c..f508408ba7062c 100644
--- a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
+++ b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
@@ -611,12 +611,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
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



More information about the cfe-commits mailing list