]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
runtime(c): compound literal braces are highlighted as errors master
authorBogdan Barbu <l4b.bogdan.barbu@gmail.com>
Tue, 4 Aug 2026 21:11:56 +0000 (21:11 +0000)
committerChristian Brabandt <cb@256bit.org>
Tue, 4 Aug 2026 21:11:56 +0000 (21:11 +0000)
Problem: Braces in C compound literals and initializers inside parentheses
         and brackets are highlighted as errors.

Solution: Recognize those initializer blocks while preserving syntax recovery
          for malformed parentheses.

fixes:  #18709
closes: #20842

Signed-off-by: Bogdan Barbu <l4b.bogdan.barbu@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
runtime/syntax/c.vim
runtime/syntax/testdir/dumps/c_initializer_00.dump [new file with mode: 0644]
runtime/syntax/testdir/input/c_initializer.c [new file with mode: 0644]

index 68381095204ecc618d1f4005917432ea805156fe..9b18c2b8a181c19d79212abc71d131dbc2743995 100644 (file)
@@ -1,7 +1,7 @@
 " Vim syntax file
 " Language:            C
 " Maintainer:          The Vim Project <https://github.com/vim/vim>
-" Last Change:         2026 Jun 01
+" Last Change:         2026 Jul 25
 " Former Maintainer:   Bram Moolenaar <Bram@vim.org>
 
 " Quit when a (custom) syntax file was already loaded
@@ -138,7 +138,7 @@ endif
 " This should be before cErrInParen to avoid problems with #define ({ xxx })
 if exists("c_curly_error")
   syn match cCurlyError "}"
-  syn region   cBlock          start="{" end="}" contains=ALLBUT,cBadBlock,cCurlyError,@cParenGroup,cErrInParen,cCppParen,cErrInBracket,cCppBracket,@cStringGroup,@Spell fold
+  syn region   cBlock          start="{" end="}" contains=ALLBUT,cBadBlock,cCurlyError,cInitBlock,@cParenGroup,cErrInParen,cCppParen,cErrInBracket,cCppBracket,@cStringGroup,@Spell fold
 else
   syn region   cBlock          start="{" end="}" transparent fold
 endif
@@ -146,7 +146,7 @@ endif
 " Catch errors caused by wrong parenthesis and brackets.
 " Also accept <% for {, %> for }, <: for [ and :> for ] (C99)
 " But avoid matching <::.
-syn cluster    cParenGroup     contains=cParenError,cIncluded,cSpecial,cCommentSkip,cCommentString,cComment2String,@cCommentGroup,cCommentStartError,cUserLabel,cBitField,cOctalZero,@cCppOutInGroup,cFormat,cNumber,cFloat,cOctal,cOctalError,cNumbersCom
+syn cluster    cParenGroup     contains=cParenError,cIncluded,cSpecial,cCommentSkip,cCommentString,cComment2String,@cCommentGroup,cCommentStartError,cUserLabel,cBitField,cOctalZero,@cCppOutInGroup,cFormat,cNumber,cFloat,cOctal,cOctalError,cNumbersCom,cBadParenBlock
 if exists("c_no_curly_error")
   if s:in_cpp_family && !exists("cpp_no_cpp11")
     syn region cParen          transparent start='(' end=')' contains=ALLBUT,@cParenGroup,cCppParen,@cStringGroup,@Spell
@@ -198,8 +198,15 @@ endif
 
 if s:ft ==# 'c' || exists("cpp_no_cpp11")
   syn region   cBadBlock       keepend start="{" end="}" contained containedin=cParen,cBracket,cBadBlock transparent fold
+  if !exists("c_no_curly_error") && !exists("c_no_bracket_error")
+    " Do not mistake an unmatched ')' followed by a block for a compound literal.
+    syn region cBadParenBlock  keepend transparent start=')\_s*\ze\%({\|<%\)' matchgroup=cErrInBracket end='}\|%>' contained containedin=cBracket,cBadBlock contains=ALLBUT,cBlock,cBadBlock,cInitBlock,@cParenGroup,cErrInParen,cCppParen,cCppBracket,@cStringGroup,@Spell
+  endif
 endif
 
+" Compound literals and initializers may appear inside parentheses or brackets.
+syn region     cInitBlock      transparent matchgroup=cInitBlock start='\%([)=]\_s*\)\@<=\%({\|<%\)' end='}\|%>' contained containedin=cParen,cBracket,cBadBlock contains=ALLBUT,cBlock,cCurlyError,@cParenGroup,cErrInParen,cCppParen,cErrInBracket,cCppBracket,@cStringGroup,@Spell,cInitBlock fold
+
 "integer number, or floating point number without a dot and with "f".
 syn case ignore
 syn match      cNumbers        display transparent "\<\d\|\.\d" contains=cNumber,cFloat,cOctalError,cOctal
diff --git a/runtime/syntax/testdir/dumps/c_initializer_00.dump b/runtime/syntax/testdir/dumps/c_initializer_00.dump
new file mode 100644 (file)
index 0000000..426a1e9
--- /dev/null
@@ -0,0 +1,20 @@
+>/+0#0000e05#ffffff0@1| |C|o|m|p|o|u|n|d| |l|i|t|e|r|a|l|s| |a|n|d| |i|n|i|t|i|a|l|i|z|e|r|s| |i|n|s|i|d|e| |e|x|p|r|e|s@1|i|o|n|s| +0#0000000&@18
+|v+0#00e0003&|o|i|d| +0#0000000&|t|e|s|t|(|v+0#00e0003&|o|i|d|)+0#0000000&| @59
+|{| @73
+@4|i+0#00e0003&|n|t| +0#0000000&|a|[|(|s+0#00e0003&|t|r|u|c|t| +0#0000000&|f|o@1|)|{| |4+0#e000002&|2| +0#0000000&|}|.|b|a|r|]|;| @40
+@4|s+0#00e0003&|t|r|u|c|t| +0#0000000&|f|o@1| |b| |=| |(@1|s+0#00e0003&|t|r|u|c|t| +0#0000000&|f|o@1|)|{| |}|)|;| @37
+@4|_+0#af5f00255&|S|t|a|t|i|c|_|a|s@1|e|r|t|(+0#0000000&|s+0#af5f00255&|i|z|e|o|f| +0#0000000&|(|i+0#00e0003&|n|t| +0#0000000&|[|]|)|{| |1+0#e000002&|,+0#0000000&| |2+0#e000002&|,+0#0000000&| |3+0#e000002&| +0#0000000&|}| |=@1| |3+0#e000002&| +0#0000000&|*| |s+0#af5f00255&|i|z|e|o|f| +0#0000000&|(|i+0#00e0003&|n|t|)+0#0000000&|,| |"+0#e000002&@1|)+0#0000000&|;| @3
+@4|f+0#af5f00255&|o|r| +0#0000000&|(|s+0#00e0003&|t|r|u|c|t| +0#0000000&|f|o@1| |i| |=| |{| |}|;@1|)| |b+0#af5f00255&|r|e|a|k|;+0#0000000&| @37
+@4|i+0#00e0003&|n|t| +0#0000000&|c|[|(|s+0#00e0003&|t|r|u|c|t| +0#0000000&|f|o@1|)| |<|%| |4+0#e000002&|2| +0#0000000&|%|>|.|b|a|r|]|;| @37
+@4|s+0#00e0003&|t|r|u|c|t| +0#0000000&|f|o@1| |d| |=| |(@1|s+0#00e0003&|t|r|u|c|t| +0#0000000&|f|o@1|)| |<|%| |%|>|)|;| @34
+@4|f|(@1|i+0#00e0003&|n|t| +0#0000000&|[|2+0#e000002&|]+0#0000000&|[|2+0#e000002&|]+0#0000000&|)|{@1| |1+0#e000002&|,+0#0000000&| |2+0#e000002&| +0#0000000&|}|,| |{| |3+0#e000002&|,+0#0000000&| |4+0#e000002&| +0#0000000&|}@1|)|;| @34
+@4|s|y|s|c|a|l@1|(|S|Y|S|_|c|l|o|c|k|_|s|e|t@1|i|m|e|,| |C|L|O|C|K|_|R|E|A|L|T|I|M|E|,| @28
+@8|t|v| |?| |&|(@1|s+0#00e0003&|t|r|u|c|t| +0#0000000&|t|i|m|e|s|p|e|c|)|{| |.|t|v|_|s|e|c| |=| |t|v|-|>|t|v|_|s|e|c|,| @19
+@12|.|t|v|_|n|s|e|c| |=| |t|v|-|>|t|v|_|u|s|e|c| |*| |1+0#e000002&|0@2| +0#0000000&|}|)| |:| |0+0#e000002&|)+0#0000000&|;| @24
+@4|f|(@1|s+0#00e0003&|t|r|u|c|t| +0#0000000&|t|i|m|e|s|p|e|c|)| @51
+@6|<|%| |.|t|v|_|s|e|c| |=| |0+0#e000002&| +0#0000000&|%|>|)|;| @49
+@4|i+0#00e0003&|n|t| +0#0000000&|e|[|)+0#ffffff16#ff404010|{| +0#0000000#ffffff0|4+0#e000002&|2| +0#0000000&|}+0#ffffff16#ff404010|.+0#0000000#ffffff0|b|a|r|]|;| @51
+@4|f|(|a| |{+0#ffffff16#ff404010| +0#0000000#ffffff0|1+0#e000002&| +0#0000000&|}+0#ffffff16#ff404010|)+0#0000000#ffffff0|;| |f|(|a|,| |{+0#ffffff16#ff404010| +0#0000000#ffffff0|1+0#e000002&| +0#0000000&|}+0#ffffff16#ff404010|)+0#0000000#ffffff0|;| @46
+|}| @73
+|~+0#4040ff13&| @73
+| +0#0000000&@56|1|,|1| @10|A|l@1| 
diff --git a/runtime/syntax/testdir/input/c_initializer.c b/runtime/syntax/testdir/input/c_initializer.c
new file mode 100644 (file)
index 0000000..a64747d
--- /dev/null
@@ -0,0 +1,18 @@
+// Compound literals and initializers inside expressions
+void test(void)
+{
+    int a[(struct foo){ 42 }.bar];
+    struct foo b = ((struct foo){ });
+    _Static_assert(sizeof (int []){ 1, 2, 3 } == 3 * sizeof (int), "");
+    for (struct foo i = { };;) break;
+    int c[(struct foo) <% 42 %>.bar];
+    struct foo d = ((struct foo) <% %>);
+    f((int [2][2]){{ 1, 2 }, { 3, 4 }});
+    syscall(SYS_clock_settime, CLOCK_REALTIME,
+        tv ? &((struct timespec){ .tv_sec = tv->tv_sec,
+            .tv_nsec = tv->tv_usec * 1000 }) : 0);
+    f((struct timespec)
+      <% .tv_sec = 0 %>);
+    int e[){ 42 }.bar];
+    f(a { 1 }); f(a, { 1 });
+}