The following two-line C++ program fails to compile with -fmodules on FreeBSD 15.0-CURRENT: #include <locale> int main() {} The command executed is: clang++ -fmodules demo.cpp The error message is: /usr/include/c++/v1/locale:730:68: error: use of undeclared identifier 'strtoll_l' Verified on FreeBSD/arm64 15.0-CURRENT, snapshot from 2025-04-22. Without -fmodules the program compiles successfully. On FreeBSD 14.2 with or without -fmodules the program compiles successfully, so this can be considered a regression. Other headers in libc++ (for example <vector> and <iostream>) include <locale> so the problem affects even programs that don't include <locale> directly.
Unfortunately I know very little about how modules work, so I won't really be able to help. It's probably better to take the problem upstream.
Any chance your current build is less than 7 hours old? We just had a commit changing the llvm build settings, see https://mail-archive.freebsd.org/cgi/getmsg.cgi?fetch=425187+0+current/freebsd-current
(In reply to Shane from comment #2) You mean: "is older than 7 hours" ? So it should be retried with a more recent build ?
I was thinking more that you just built current and the change may have introduced this result, but yeah the other way of it fixing this issue could be possible.
Tested on arm64 with the following FreeBSD versions: 15.0-CURRENT (official snapshot from 2025-05-08): problem still present 14.3-BETA2 (official install image): problem present 13.5-RELEASE (official install image): problem present
FYI: Note: I named things to use: -fmodules fmodules-test.cpp # grep -r strtoll_l /usr/include/ | less /usr/include/c++/v1/locale: long long __ll = strtoll_l(__a, &__p2, __base, _LIBCPP_GET_C_LOCALE); /usr/include/c++/v1/__locale_dir/locale_base_api.h:long long strtoll_l(const char* str, char** str_end, locale_t); /usr/include/xlocale/_stdlib.h:long long strtoll_l(const char *, char **, int, locale_t); FYI for the /usr/include/c++/v1/locale use of strtoll_l: template <class _Tp> _LIBCPP_HIDE_FROM_ABI _Tp __num_get_signed_integral(const char* __a, const char* __a_end, ios_base::iostate& __err, int __base) { if (__a != __a_end) { __libcpp_remove_reference_t<decltype(errno)> __save_errno = errno; errno = 0; char* __p2; long long __ll = strtoll_l(__a, &__p2, __base, _LIBCPP_GET_C_LOCALE); . . . So, as stands, only *.h headers declare strtoll_l . I got clang++19 installed on a Linux and it got: $ grep -r strtoll_l /usr/lib/llvm-19/include/c++/v1/ /usr/lib/llvm-19/include/c++/v1/locale: long long __ll = strtoll_l(__a, &__p2, __base, _LIBCPP_GET_C_LOCALE); /usr/lib/llvm-19/include/c++/v1/__support/xlocale/__strtonum_fallback.h:inline _LIBCPP_HIDE_FROM_ABI long long strtoll_l(const char* __nptr, char** __endptr, int __base, locale_t) { /usr/lib/llvm-19/include/c++/v1/__locale_dir/locale_base_api.h:long long strtoll_l(const char* str, char** str_end, locale_t); /usr/lib/llvm-19/include/c++/v1/__locale_dir/locale_base_api/ibm.h:inline _LIBCPP_HIDE_FROM_ABI long long strtoll_l(const char* __nptr, char** __endptr, int __base, locale_t locale) { /usr/lib/llvm-19/include/c++/v1/__locale_dir/locale_base_api/musl.h:inline _LIBCPP_HIDE_FROM_ABI long long strtoll_l(const char* __nptr, char** __endptr, int __base, locale_t) { /usr/lib/llvm-19/include/c++/v1/__locale_dir/locale_base_api/win32.h:#define strtoll_l _strtoi64_l It was able to execute: $ clang++-19 -fmodules fmodules-test.cpp $ without complaints. But on FreeBSD [main] there was no __strtonum_fallback.h : # find -s / -name __strtonum_fallback.h -print #
Created attachment 260449 [details] A fix for the problem I'm attaching a patch that fixes the problem. Here is my analysis of the problem: The libc++ header <locale> needs symbols like strtoll_l() or sscanf_l(). The header file <xlocale.h> provides those symbols if it is included *after* <stdio.h> and <stdlib.h>. When compiling without clang modules (which is the default), the header <locale> includes many other headers which transitively include <stdio.h> and <stdlib.h>. So, when the line in <locale> that includes <xlocale.h> is reached, the necessary prerequisite headers have already been included. When compiling with clang modules the header <xlocale.h> is included from two submodules. The inclusion in /usr/include/c++/v1/__locale_dir/locale_base_api.h is done without first including <stdio.h> and <stdlib.h> and therefore doesn't provide the necessary symbols. The inclusion in <locale> is considered a semantic import of the submodule defined by __locale_dir/locale_base_api.h. If you remove the include line for <xlocale.h> from __locale_dir/locale_base_api.h, the header <xlocale.h> will no longer be considered as belonging to the submodule defined by __locale_dir/locale_base_api.h and the include for <xlocale.h> in <locale> will properly provide the necessary symbols.
(In reply to Jordan Gordeev from comment #7) Are you going to submit this upstream? The proposed change is not to FreeBSD-specific code but to upstream code that is imported.
Created attachment 260505 [details] Improved patch suitable for FreeBSD 14.3 I'm attaching a new patch. The improvement over the previous patch is that when compiling without clang modules the change from the patch is negligible. This patch is suitable for inclusion in FreeBSD 14.3 which is close to being released. It is also suitable for 15.0-CURRENT. The patch relies on __has_feature(modules) compile-time check which can tell us if we are compiling with clang modules or not. The check allows riskier changes to be applied only for the case they are trying to fix ("with clang modules") and leave the other case ("without clang modules") unaffected. Adding this kind of check to libc++ code is not a big deal since there already is such a check in /usr/include/c++/v1/__config. To validate the effect of the patch when compiling without clang modules, compare the output of "clang++ -E demo.cpp" before and after applying the patch. The only observable changes are some line numbers in locale_base_api.h shifting slightly due to the addition of 6 extra lines.
(In reply to Jordan Gordeev from comment #9) I do not know if FreeBSD or libc++ target more than clang++ and g++ versions for compatibility. __has_feature(x) is not from the language standard, any version) but g++ has explicitly added support for clang++ compatibility. https://clang.llvm.org/docs/LanguageExtensions.html#has-feature-and-has-extension documents a usage technique via the text: #ifndef __has_feature // Optional of course. #define __has_feature(x) 0 // Compatibility with non-clang compilers. #endif #ifndef __has_extension #define __has_extension __has_feature // Compatibility with pre-3.0 compilers. #endif ... #if __has_feature(cxx_rvalue_references) // This code will only be compiled with the -std=c++11 and -std=gnu++11 // options, because rvalue references are only standardized in C++11. #endif #if __has_extension(cxx_rvalue_references) // This code will be compiled with the -std=c++11, -std=gnu++11, -std=c++98 // and -std=gnu++98 options, because rvalue references are supported as a // language extension in C++98. #endif
A commit in branch main references this bug: URL: https://cgit.FreeBSD.org/src/commit/?id=c809b0184d0a6543bc5327d4252fa56a07ce4689 commit c809b0184d0a6543bc5327d4252fa56a07ce4689 Author: Jordan Gordeev <jgopensource@proton.me> AuthorDate: 2025-05-18 19:55:05 +0000 Commit: Dimitry Andric <dim@FreeBSD.org> CommitDate: 2025-05-18 20:04:42 +0000 libc++: fix compiling <locale> with -fmodules In /usr/include/c++/v1/__locale_dir/locale_base_api.h, xlocale.h is included without first including stdio.h and stdlib.h, which causes functions like strtoll_l() or sscanf_l() to not be declared. When compiling with -fmodules, locale_base_api.h is processed separately due to a declaration in /usr/include/c++/v1/module.modulemap, and this will cause errors due to the above undeclared symbols. Meanwhile, upstream has substantially reorganized this part of libc++'s headers, so apply a minimalistic workaround: specifically when compiling with -fmodules, add includes of stdio.h and stdlib.h. PR: 286342 MFC after: 1 week .../llvm-project/libcxx/include/__locale_dir/locale_base_api.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
A commit in branch stable/14 references this bug: URL: https://cgit.FreeBSD.org/src/commit/?id=cab029073dc6cb5814df44556e585b8fdb1c9846 commit cab029073dc6cb5814df44556e585b8fdb1c9846 Author: Jordan Gordeev <jgopensource@proton.me> AuthorDate: 2025-05-18 19:55:05 +0000 Commit: Dimitry Andric <dim@FreeBSD.org> CommitDate: 2025-05-25 09:20:32 +0000 libc++: fix compiling <locale> with -fmodules In /usr/include/c++/v1/__locale_dir/locale_base_api.h, xlocale.h is included without first including stdio.h and stdlib.h, which causes functions like strtoll_l() or sscanf_l() to not be declared. When compiling with -fmodules, locale_base_api.h is processed separately due to a declaration in /usr/include/c++/v1/module.modulemap, and this will cause errors due to the above undeclared symbols. Meanwhile, upstream has substantially reorganized this part of libc++'s headers, so apply a minimalistic workaround: specifically when compiling with -fmodules, add includes of stdio.h and stdlib.h. PR: 286342 MFC after: 1 week (cherry picked from commit c809b0184d0a6543bc5327d4252fa56a07ce4689) .../llvm-project/libcxx/include/__locale_dir/locale_base_api.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
A commit in branch stable/13 references this bug: URL: https://cgit.FreeBSD.org/src/commit/?id=1c12934eba86c7294becc23c7518e0fb9b996fa8 commit 1c12934eba86c7294becc23c7518e0fb9b996fa8 Author: Jordan Gordeev <jgopensource@proton.me> AuthorDate: 2025-05-18 19:55:05 +0000 Commit: Dimitry Andric <dim@FreeBSD.org> CommitDate: 2025-05-25 09:20:41 +0000 libc++: fix compiling <locale> with -fmodules In /usr/include/c++/v1/__locale_dir/locale_base_api.h, xlocale.h is included without first including stdio.h and stdlib.h, which causes functions like strtoll_l() or sscanf_l() to not be declared. When compiling with -fmodules, locale_base_api.h is processed separately due to a declaration in /usr/include/c++/v1/module.modulemap, and this will cause errors due to the above undeclared symbols. Meanwhile, upstream has substantially reorganized this part of libc++'s headers, so apply a minimalistic workaround: specifically when compiling with -fmodules, add includes of stdio.h and stdlib.h. PR: 286342 MFC after: 1 week (cherry picked from commit c809b0184d0a6543bc5327d4252fa56a07ce4689) .../llvm-project/libcxx/include/__locale_dir/locale_base_api.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
A commit in branch releng/14.3 references this bug: URL: https://cgit.FreeBSD.org/src/commit/?id=a0d22d7934c697d8af90f1a7f902e13dcf9b3a60 commit a0d22d7934c697d8af90f1a7f902e13dcf9b3a60 Author: Jordan Gordeev <jgopensource@proton.me> AuthorDate: 2025-05-18 19:55:05 +0000 Commit: Dimitry Andric <dim@FreeBSD.org> CommitDate: 2025-05-28 16:26:27 +0000 libc++: fix compiling <locale> with -fmodules In /usr/include/c++/v1/__locale_dir/locale_base_api.h, xlocale.h is included without first including stdio.h and stdlib.h, which causes functions like strtoll_l() or sscanf_l() to not be declared. When compiling with -fmodules, locale_base_api.h is processed separately due to a declaration in /usr/include/c++/v1/module.modulemap, and this will cause errors due to the above undeclared symbols. Meanwhile, upstream has substantially reorganized this part of libc++'s headers, so apply a minimalistic workaround: specifically when compiling with -fmodules, add includes of stdio.h and stdlib.h. PR: 286342 Approved by: re (cperciva) MFC after: 1 week (cherry picked from commit c809b0184d0a6543bc5327d4252fa56a07ce4689) (cherry picked from commit cab029073dc6cb5814df44556e585b8fdb1c9846) .../llvm-project/libcxx/include/__locale_dir/locale_base_api.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)