__thread Foo foo;
Как "нечто" на самом деле разрешено? Компилятор тихо заменяет каждый экземпляр "нечто" с вызовом функции? "Нечто" хранится где-нибудь относительно дна стека, и компилятор хранит это, поскольку "эй, для каждого потока, имейте это пространство около дна стека, и нечто хранится, как 'смещено x от дна стека'"?
Это немного сложно (этот документ объясняет это очень подробно), но по сути это не так. Вместо этого компилятор помещает в исполняемый файл специальный раздел .tdata, который содержит все переменные, локальные для потока. Во время выполнения создается новая секция данных для каждого потока с копией данных в секции .tdata (доступной только для чтения), а когда потоки переключаются во время выполнения, секция также автоматически переключается.
В итоге переменные __thread работают так же быстро, как и обычные переменные, и не занимают лишнего места в стеке.