Skip to content

Commit 1afdcda

Browse files
committed
[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 ^ ```
1 parent ec56c92 commit 1afdcda

File tree

4 files changed

+74
-7
lines changed

4 files changed

+74
-7
lines changed

clang/docs/InternalsManual.rst

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3364,7 +3364,7 @@ Multiple occurrences accumulate prefixes. For example,
33643364

33653365
Specifying Diagnostics
33663366
^^^^^^^^^^^^^^^^^^^^^^
3367-
Indicating that a line expects an error or a warning is simple. Put a comment
3367+
Indicating that a line expects an error or a warning is easy. Put a comment
33683368
on the line that has the diagnostic, use
33693369
``expected-{error,warning,remark,note}`` to tag if it's an expected error,
33703370
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
33733373
should be included in test cases unless there is a compelling reason to use
33743374
truncated text instead.)
33753375

3376+
For a full description of the matching behavior, including more complex
3377+
matching scenarios, see :ref:`matching <DiagnosticMatching>` below.
3378+
33763379
Here's an example of the most commonly used way to specify expected
33773380
diagnostics:
33783381

@@ -3458,8 +3461,33 @@ A range can also be specified by ``<n>-<m>``. For example:
34583461

34593462
In this example, the diagnostic may appear only once, if at all.
34603463

3464+
.. _DiagnosticMatching:
3465+
3466+
Matching Modes
3467+
~~~~~~~~~~~~~~
3468+
3469+
The default matching mode is simple string, which looks for the expected text
3470+
that appears between the first `{{` and `}}` pair of the comment. The string is
3471+
interpreted just as-is, with one exception: the sequence `\n` is converted to a
3472+
single newline character. This mode matches the emitted diagnostic when the
3473+
text appears as a substring at any position of the emitted message.
3474+
3475+
To enable matching against desired strings that contain `}}` or `{{`, the
3476+
string-mode parser accepts opening delimiters of more than two curly braces,
3477+
like `{{{`. It then looks for a closing delimiter of equal "width" (i.e `}}}`).
3478+
For example:
3479+
3480+
.. code-block:: c++
3481+
3482+
// expected-note {{{evaluates to '{{2, 3, 4}} == {0, 3, 4}'}}}
3483+
3484+
The intent is to allow the delimeter to be wider than the longest `{` or `}`
3485+
brace sequence in the content, so that if your expected text contains `{{{`
3486+
(three braces) it may be delimited with `{{{{` (four braces), and so on.
3487+
34613488
Regex matching mode may be selected by appending ``-re`` to the diagnostic type
3462-
and including regexes wrapped in double curly braces in the directive, such as:
3489+
and including regexes wrapped in double curly braces (`{{` and `}}`) in the
3490+
directive, such as:
34633491

34643492
.. code-block:: text
34653493
@@ -3471,6 +3499,8 @@ Examples matching error: "variable has incomplete type 'struct s'"
34713499

34723500
// expected-error {{variable has incomplete type 'struct s'}}
34733501
// expected-error {{variable has incomplete type}}
3502+
// expected-error {{{variable has incomplete type}}}
3503+
// expected-error {{{{variable has incomplete type}}}}
34743504

34753505
// expected-error-re {{variable has type 'struct {{.}}'}}
34763506
// expected-error-re {{variable has type 'struct {{.*}}'}}

clang/include/clang/Basic/DiagnosticFrontendKinds.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ def err_verify_no_such_marker : Error<
167167
def err_verify_missing_start : Error<
168168
"cannot find start ('{{') of expected %0">;
169169
def err_verify_missing_end : Error<
170-
"cannot find end ('}}') of expected %0">;
170+
"cannot find end ('%1') of expected %0">;
171171
def err_verify_invalid_content : Error<
172172
"invalid expected %0: %1">;
173173
def err_verify_missing_regex : Error<

clang/lib/Frontend/VerifyDiagnosticConsumer.cpp

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -611,12 +611,19 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
611611
diag::err_verify_missing_start) << KindStr;
612612
continue;
613613
}
614+
llvm::SmallString<8> CloseBrace("}}");
615+
const char *const DelimBegin = PH.C;
614616
PH.Advance();
617+
// Count the number of opening braces for `string` kinds
618+
for (; !D.RegexKind && PH.Next("{"); PH.Advance())
619+
CloseBrace += '}';
615620
const char* const ContentBegin = PH.C; // mark content begin
616-
// Search for token: }}
617-
if (!PH.SearchClosingBrace("{{", "}}")) {
618-
Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
619-
diag::err_verify_missing_end) << KindStr;
621+
// Search for closing brace
622+
StringRef OpenBrace(DelimBegin, ContentBegin - DelimBegin);
623+
if (!PH.SearchClosingBrace(OpenBrace, CloseBrace)) {
624+
Diags.Report(Pos.getLocWithOffset(PH.C - PH.Begin),
625+
diag::err_verify_missing_end)
626+
<< KindStr << CloseBrace;
620627
continue;
621628
}
622629
const char* const ContentEnd = PH.P; // mark content end

clang/test/Frontend/verify.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,3 +157,33 @@ unexpected b; // expected-error@33 1-1 {{unknown type}}
157157
// what-error {{huh?}}
158158
// CHECK9: error: 'what-error' diagnostics expected but not seen:
159159
#endif
160+
161+
#ifdef TEST_WIDE_DELIM
162+
// RUN: not %clang_cc1 -DTEST_WIDE_DELIM -verify %s 2>&1 | FileCheck -check-prefix=CHECK-WIDE-DELIM %s
163+
164+
// expected-error {{{some message with {{}} in it}}}
165+
// expected-error {{{some message with {}} in it}}}
166+
// expected-error {{{some message with {{} in it}}}
167+
168+
// expected-error-re {{{some {{.*}} regex with double braces}}}
169+
// expected-error-re {{{some message with {{} in it}}}
170+
171+
// expected-error {{{mismatched delim}}
172+
// expected-error-re {{{mismatched re {{.*} }}}
173+
// expected-error-re {{{no regex}}}
174+
175+
#if 0
176+
// CHECK-WIDE-DELIM: error: 'expected-error' diagnostics expected but not seen:
177+
// CHECK-WIDE-DELIM-NEXT: verify.c Line 164: some message with {{[{]{}[}]}} in it
178+
// CHECK-WIDE-DELIM-NEXT: verify.c Line 165: some message with {}} in it
179+
// CHECK-WIDE-DELIM-NEXT: verify.c Line 166: some message with {{[{]{[}]}} in it
180+
// CHECK-WIDE-DELIM-NEXT: verify.c Line 168: {some {{.*}} regex with double braces
181+
// CHECK-WIDE-DELIM-NEXT: error: 'expected-error' diagnostics seen but not expected:
182+
// CHECK-WIDE-DELIM-NEXT: verify.c Line 169: cannot find end ('}}') of expected regex
183+
// CHECK-WIDE-DELIM-NEXT: verify.c Line 171: cannot find end ('}}}') of expected string
184+
// CHECK-WIDE-DELIM-NEXT: verify.c Line 172: cannot find end ('}}') of expected regex
185+
// CHECK-WIDE-DELIM-NEXT: verify.c Line 173: cannot find start of regex ('{{[{][{]}}') in {no regex
186+
// CHECK-WIDE-DELIM-NEXT: 8 errors generated.
187+
#endif
188+
189+
#endif

0 commit comments

Comments
 (0)