1: Sample code that reproduces the problem.
typeof_unqual(*u"") a[8] = U"x";
2: Exact command used to run SDCC on this sample code.
sdcc -mz80 --std=c2y --nostdinc -S bug.c -o bug.asm
3: SDCC version tested.
SDCC 4.6.4 #17064 (Linux), tested 21 October 2026.
4: Observed and expected behaviour.
The array element type comes from a UTF-16 string literal, but its initialiser
is a UTF-32 string literal. The corresponding encoding prefixes differ. SDCC
silently accepts both u-to-U and U-to-u mismatches, including empty strings,
braces and block scope, in the reported primary cases. Each valid case uses
the matching prefix. The bound of eight leaves ample capacity and avoids the
unrelated excess-elements warning seen with unknown-size arrays. A const-
qualified variant receives error 69 everywhere; a typedef variant receives
error 69 on some ports and is silent on others. Those outcomes are listed
separately, rather than counted as universally missing diagnostics. The report
concerns the absent ISO diagnostic; no runtime result is claimed. L-versus-u
cases are excluded because wchar_t and char16_t can share a compatible
underlying type on a target.
WG14 N3886,
6.7.11 paragraph 7, requires the corresponding encoding prefix for a wide
string literal array initialiser. A diagnostic is expected for this mismatch.
typeof_unqual(*u"") obtains the array element type without assuming which
unsigned integer type implements char16_t on the target.
5: Additional checks.
The sample is silently accepted on Z80, MCS51 default, STM8 default, PDK14 and MOS65C02 in C2Y mode. These are translation and diagnostic checks; no runtime result is claimed.
Compiler Explorer: SDCC 4.6.0, SDCC trunk and GCC 16.2. All three panes use the sample above. The saved source, compiler selections and options were round-trip verified on 21 October 2026. Both SDCC panes use -mz80 --std=c2y; GCC uses -std=c2y -pedantic-errors -fsyntax-only. The public trunk build is r17013, distinct from the local r17064 retest.
| CE compiler | Observed result |
|---|---|
| SDCC 4.6.0 | Accepted silently |
| SDCC trunk r17013 | Accepted silently |
| GCC 16.2 | Rejected with diagnostics |
| Case | Expected | Current SDCC results |
|---|---|---|
utf16-braced-utf32.c |
Diagnostic required | Accepted silently on all five targets |
utf16-const-utf32.c |
Diagnostic required | Diagnostic 69 on all five targets |
utf16-control.c |
Valid | Accepted silently on all five targets |
utf16-empty-control.c |
Valid | Accepted silently on all five targets |
utf16-empty-utf32.c |
Diagnostic required | Accepted silently on all five targets |
utf16-from-utf32.c |
Diagnostic required | Accepted silently on all five targets |
utf16-local-utf32.c |
Diagnostic required | Accepted silently on all five targets |
utf16-typedef-utf32.c |
Diagnostic required | Diagnostic 69 on z80, stm8, mos65c02; Accepted silently on mcs51, pdk14 |
utf32-braced-control.c |
Valid | Accepted silently on all five targets |
utf32-control.c |
Valid | Accepted silently on all five targets |
utf32-empty-utf16.c |
Diagnostic required | Accepted silently on all five targets |
utf32-from-utf16.c |
Diagnostic required | Accepted silently on all five targets |
Related report: [bugs:#2791]. That report concerned rejection of a valid matching-prefix wide-string initialiser; this report concerns missing diagnostics for mismatched prefixes.
"L-versus-u cases are excluded because wchar_t and char16_t can share a compatible underlying type on a target." - sure, but isn't that true for all of them? char could be the same as char16_t, same as char32_t, same as wchar_t? AFAIR, many years ago, SDCC did indeed have an 8-bit wchar_t. These days, SDCC has a 32-bit wchar_t.
I think that part of the report is flawed; however, my understanding is that
charis required to be distinct fromunsigned charandsigned char, therefore it could not literally be the same aschar16_torchar32_t.Anyway, what matters is the types that SDCC actually uses to implement
char16_t,char32_tandwchar_t-- not the theoretical possibility that some or all of those types might be compatible in other implementations.The first patch that Codex suggested had an unmotivated gap in test coverage: it did not add tests to check incompatible
L/u(32-bitunsigned longvs. 16-bitunsigned int) initialisation in either direction.Ah, yes.
char, is not an unsigned integer type (and neither it is a signed one). So only wchar_t can be char (like it used to).Please consider the attached candidate bug fix created in negotiation with Codex.
It selects tests by language features and select compatible element types with
_Genericinstead of assuming compiler-specificwchar_ttypes. The tests now cover incompatibleL/uinitialisation in both directions, at file and block scope, with and without braces, and matching wide strings.