1: Sample code that reproduces the problem.
static _Thread_local int 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 #17068 (Linux), tested 23 October 2026.
4: Observed and expected behaviour.
SDCC reports error 255, thread-local storage is not implemented, followed by:
Internal error: validateLink failed in DCL_TYPE(decl) @ /home/sdcc-builder/build/sdcc-build/orig/sdcc/src/SDCCsymt.c:959: expected DECLARATOR, got null-link
The process exits with status 1. No signal termination was observed. This is an internal validation error after an ordinary unsupported-feature diagnostic, not a claim that the compiler crashes or silently accepts the declaration.
If thread-local storage remains unsupported, SDCC should retain its ordinary diagnostic and reject the input without an internal validation failure. This report does not request implementation of thread-local storage. The source declaration itself is permitted by ISO C when the facility is supported.
5: Additional checks.
The same internal validation failure occurs on Z80, MCS51, STM8, PDK14 and MOS65C02 in C23 and C2Y for six forms: the file-scope static object, a block-scope declaration without static/extern, a function declaration, an object redeclaration omitting _Thread_local, a redeclaration introducing _Thread_local, and a static thread-local VLA object. That is 60 reproduced error paths. The nearby non-thread-local static object compiles silently on all five targets in both modes.
GCC 13.3.0 with -std=c2x -pedantic-errors -fsyntax-only accepts the sample. GCC 16.2 and Clang were not tested.
Is this even a bug? We emit the diagnostic, so the user gets notified that SDCC does not support thread-local storage (and unlike
_Atomic, I don't think we'll support thread-local storage anytime soon). Might not be worth the effort getting rid of the subsequent internal error.Last edit: Philipp Klaus Krause 2026-10-24
I wondered the same thing. Unfortunately, it looks like a bug, even if it is behaving as intended.
Personally, I do not consider this an (impotant) bug to solve. The second error is a result of the first one. Fix the first and the second goes away. I would not recommend every internal error to be interpreted as a bug when faulty input is the underlying issue and has been diagnosed already. But if you must, you can abort after the first error and stop diagnosing the rest of the input.
Given lower priority