-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[C2y] Add stdcountof.h #140890
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
[C2y] Add stdcountof.h #140890
Conversation
WG14 N3469 changed _Lengthof to _Countof but it also introduced the <stdcountof.h> header to expose a macro with a non-ugly identifier. GCC vends this header as part of the compiler implementation, so Clang should do the same.
@llvm/pr-subscribers-clang-modules @llvm/pr-subscribers-clang Author: Aaron Ballman (AaronBallman) ChangesWG14 N3469 changed _Lengthof to _Countof but it also introduced the <stdcountof.h> header to expose a macro with a non-ugly identifier. GCC vends this header as part of the compiler implementation, so Clang should do the same. Full diff: https://github.com/llvm/llvm-project/pull/140890.diff 3 Files Affected:
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index b466f3758e0b6..7b2777f711b8d 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -249,7 +249,9 @@ C2y Feature Support
a conforming extension in earlier C language modes, but not in C++ language
modes (``std::extent`` and ``std::size`` already provide the same
functionality but with more granularity). The feature can be tested via
- ``__has_feature(c_countof)`` or ``__has_extension(c_countof)``.
+ ``__has_feature(c_countof)`` or ``__has_extension(c_countof)``. This also
+ adds the ``<stdcountof.h>`` header file which exposes the ``countof`` macro
+ which expands to ``_Countof``.
C23 Feature Support
^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/Headers/stdcountof.h b/clang/lib/Headers/stdcountof.h
new file mode 100644
index 0000000000000..5714e6d6ff860
--- /dev/null
+++ b/clang/lib/Headers/stdcountof.h
@@ -0,0 +1,15 @@
+/*===---- stdcountof.h - Standard header for countof -----------------------===
+ *
+ * Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+ * See https://llvm.org/LICENSE.txt for license information.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ *
+ *===-----------------------------------------------------------------------===
+ */
+
+#ifndef __STDCOUNTOF_H
+#define __STDCOUNTOF_H
+
+#define countof _Countof
+
+#endif /* __STDCOUNTOF_H */
diff --git a/clang/test/C/C2y/n3469.c b/clang/test/C/C2y/n3469.c
index 3d9ac8e6411e9..4660596614075 100644
--- a/clang/test/C/C2y/n3469.c
+++ b/clang/test/C/C2y/n3469.c
@@ -1,9 +1,9 @@
-// RUN: %clang_cc1 -fsyntax-only -std=c2y -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c2y -verify -ffreestanding %s
/* WG14 N3469: Clang 21
* The Big Array Size Survey
*
- * This renames _Lengthof to _Countof.
+ * This renames _Lengthof to _Countof and introduces the stdcountof.h header.
*/
void test() {
@@ -12,3 +12,12 @@ void test() {
expected-error {{expected expression}}
}
+#ifdef countof
+#error "why is countof defined as a macro?"
+#endif
+
+#include <stdcountof.h>
+
+#ifndef countof
+#error "why is countof not defined as a macro?"
+#endif
|
Precommit CI caught a relevant failure that only happens when testing against an install target, so yay for that! I've got a fix coming along with some other updated support files I found when looking at stdalign.h |
You can test this locally with the following command:git-clang-format --diff HEAD~1 HEAD --extensions h,c,cpp -- clang/lib/Headers/stdcountof.h clang/lib/Lex/ModuleMap.cpp clang/lib/Lex/PPDirectives.cpp clang/test/C/C2y/n3469.c View the diff from clang-format here.diff --git a/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp
index be9cab8af..aea71808f 100644
--- a/clang/lib/Lex/ModuleMap.cpp
+++ b/clang/lib/Lex/ModuleMap.cpp
@@ -253,19 +253,19 @@ OptionalFileEntryRef ModuleMap::findHeader(
/// headers.
static bool isBuiltinHeaderName(StringRef FileName) {
return llvm::StringSwitch<bool>(FileName)
- .Case("float.h", true)
- .Case("iso646.h", true)
- .Case("limits.h", true)
- .Case("stdalign.h", true)
- .Case("stdarg.h", true)
- .Case("stdatomic.h", true)
- .Case("stdbool.h", true)
- .Case("stdcountof.h", true)
- .Case("stddef.h", true)
- .Case("stdint.h", true)
- .Case("tgmath.h", true)
- .Case("unwind.h", true)
- .Default(false);
+ .Case("float.h", true)
+ .Case("iso646.h", true)
+ .Case("limits.h", true)
+ .Case("stdalign.h", true)
+ .Case("stdarg.h", true)
+ .Case("stdatomic.h", true)
+ .Case("stdbool.h", true)
+ .Case("stdcountof.h", true)
+ .Case("stddef.h", true)
+ .Case("stdint.h", true)
+ .Case("tgmath.h", true)
+ .Case("unwind.h", true)
+ .Default(false);
}
/// Determine whether the given module name is the name of a builtin
diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp
index 68f9ca9cb..502dd015a 100644
--- a/clang/lib/Lex/PPDirectives.cpp
+++ b/clang/lib/Lex/PPDirectives.cpp
@@ -248,50 +248,58 @@ static bool warnByDefaultOnWrongCase(StringRef Include) {
// The standard C/C++ and Posix headers
return llvm::StringSwitch<bool>(LowerInclude)
- // C library headers
- .Cases("assert.h", "complex.h", "ctype.h", "errno.h", "fenv.h", true)
- .Cases("float.h", "inttypes.h", "iso646.h", "limits.h", "locale.h", true)
- .Cases("math.h", "setjmp.h", "signal.h", "stdalign.h", "stdarg.h", true)
- .Cases("stdatomic.h", "stdbool.h", "stdckdint.h", "stdcountof.h", true)
- .Cases("stddef.h", "stdint.h", "stdio.h", "stdlib.h", "stdnoreturn.h", true)
- .Cases("string.h", "tgmath.h", "threads.h", "time.h", "uchar.h", true)
- .Cases("wchar.h", "wctype.h", true)
-
- // C++ headers for C library facilities
- .Cases("cassert", "ccomplex", "cctype", "cerrno", "cfenv", true)
- .Cases("cfloat", "cinttypes", "ciso646", "climits", "clocale", true)
- .Cases("cmath", "csetjmp", "csignal", "cstdalign", "cstdarg", true)
- .Cases("cstdbool", "cstddef", "cstdint", "cstdio", "cstdlib", true)
- .Cases("cstring", "ctgmath", "ctime", "cuchar", "cwchar", true)
- .Case("cwctype", true)
-
- // C++ library headers
- .Cases("algorithm", "fstream", "list", "regex", "thread", true)
- .Cases("array", "functional", "locale", "scoped_allocator", "tuple", true)
- .Cases("atomic", "future", "map", "set", "type_traits", true)
- .Cases("bitset", "initializer_list", "memory", "shared_mutex", "typeindex", true)
- .Cases("chrono", "iomanip", "mutex", "sstream", "typeinfo", true)
- .Cases("codecvt", "ios", "new", "stack", "unordered_map", true)
- .Cases("complex", "iosfwd", "numeric", "stdexcept", "unordered_set", true)
- .Cases("condition_variable", "iostream", "ostream", "streambuf", "utility", true)
- .Cases("deque", "istream", "queue", "string", "valarray", true)
- .Cases("exception", "iterator", "random", "strstream", "vector", true)
- .Cases("forward_list", "limits", "ratio", "system_error", true)
-
- // POSIX headers (which aren't also C headers)
- .Cases("aio.h", "arpa/inet.h", "cpio.h", "dirent.h", "dlfcn.h", true)
- .Cases("fcntl.h", "fmtmsg.h", "fnmatch.h", "ftw.h", "glob.h", true)
- .Cases("grp.h", "iconv.h", "langinfo.h", "libgen.h", "monetary.h", true)
- .Cases("mqueue.h", "ndbm.h", "net/if.h", "netdb.h", "netinet/in.h", true)
- .Cases("netinet/tcp.h", "nl_types.h", "poll.h", "pthread.h", "pwd.h", true)
- .Cases("regex.h", "sched.h", "search.h", "semaphore.h", "spawn.h", true)
- .Cases("strings.h", "stropts.h", "sys/ipc.h", "sys/mman.h", "sys/msg.h", true)
- .Cases("sys/resource.h", "sys/select.h", "sys/sem.h", "sys/shm.h", "sys/socket.h", true)
- .Cases("sys/stat.h", "sys/statvfs.h", "sys/time.h", "sys/times.h", "sys/types.h", true)
- .Cases("sys/uio.h", "sys/un.h", "sys/utsname.h", "sys/wait.h", "syslog.h", true)
- .Cases("tar.h", "termios.h", "trace.h", "ulimit.h", true)
- .Cases("unistd.h", "utime.h", "utmpx.h", "wordexp.h", true)
- .Default(false);
+ // C library headers
+ .Cases("assert.h", "complex.h", "ctype.h", "errno.h", "fenv.h", true)
+ .Cases("float.h", "inttypes.h", "iso646.h", "limits.h", "locale.h", true)
+ .Cases("math.h", "setjmp.h", "signal.h", "stdalign.h", "stdarg.h", true)
+ .Cases("stdatomic.h", "stdbool.h", "stdckdint.h", "stdcountof.h", true)
+ .Cases("stddef.h", "stdint.h", "stdio.h", "stdlib.h", "stdnoreturn.h",
+ true)
+ .Cases("string.h", "tgmath.h", "threads.h", "time.h", "uchar.h", true)
+ .Cases("wchar.h", "wctype.h", true)
+
+ // C++ headers for C library facilities
+ .Cases("cassert", "ccomplex", "cctype", "cerrno", "cfenv", true)
+ .Cases("cfloat", "cinttypes", "ciso646", "climits", "clocale", true)
+ .Cases("cmath", "csetjmp", "csignal", "cstdalign", "cstdarg", true)
+ .Cases("cstdbool", "cstddef", "cstdint", "cstdio", "cstdlib", true)
+ .Cases("cstring", "ctgmath", "ctime", "cuchar", "cwchar", true)
+ .Case("cwctype", true)
+
+ // C++ library headers
+ .Cases("algorithm", "fstream", "list", "regex", "thread", true)
+ .Cases("array", "functional", "locale", "scoped_allocator", "tuple", true)
+ .Cases("atomic", "future", "map", "set", "type_traits", true)
+ .Cases("bitset", "initializer_list", "memory", "shared_mutex",
+ "typeindex", true)
+ .Cases("chrono", "iomanip", "mutex", "sstream", "typeinfo", true)
+ .Cases("codecvt", "ios", "new", "stack", "unordered_map", true)
+ .Cases("complex", "iosfwd", "numeric", "stdexcept", "unordered_set", true)
+ .Cases("condition_variable", "iostream", "ostream", "streambuf",
+ "utility", true)
+ .Cases("deque", "istream", "queue", "string", "valarray", true)
+ .Cases("exception", "iterator", "random", "strstream", "vector", true)
+ .Cases("forward_list", "limits", "ratio", "system_error", true)
+
+ // POSIX headers (which aren't also C headers)
+ .Cases("aio.h", "arpa/inet.h", "cpio.h", "dirent.h", "dlfcn.h", true)
+ .Cases("fcntl.h", "fmtmsg.h", "fnmatch.h", "ftw.h", "glob.h", true)
+ .Cases("grp.h", "iconv.h", "langinfo.h", "libgen.h", "monetary.h", true)
+ .Cases("mqueue.h", "ndbm.h", "net/if.h", "netdb.h", "netinet/in.h", true)
+ .Cases("netinet/tcp.h", "nl_types.h", "poll.h", "pthread.h", "pwd.h",
+ true)
+ .Cases("regex.h", "sched.h", "search.h", "semaphore.h", "spawn.h", true)
+ .Cases("strings.h", "stropts.h", "sys/ipc.h", "sys/mman.h", "sys/msg.h",
+ true)
+ .Cases("sys/resource.h", "sys/select.h", "sys/sem.h", "sys/shm.h",
+ "sys/socket.h", true)
+ .Cases("sys/stat.h", "sys/statvfs.h", "sys/time.h", "sys/times.h",
+ "sys/types.h", true)
+ .Cases("sys/uio.h", "sys/un.h", "sys/utsname.h", "sys/wait.h", "syslog.h",
+ true)
+ .Cases("tar.h", "termios.h", "trace.h", "ulimit.h", true)
+ .Cases("unistd.h", "utime.h", "utmpx.h", "wordexp.h", true)
+ .Default(false);
}
/// Find a similar string in `Candidates`.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still have no problem with this, but it is now into things I have zero confidence reviewing :) Please have someone who has ever used modules review this.
@@ -252,8 +252,8 @@ static bool warnByDefaultOnWrongCase(StringRef Include) { | |||
.Cases("assert.h", "complex.h", "ctype.h", "errno.h", "fenv.h", true) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The fact that these aren't tablegened somewhere is frightening!
@@ -260,6 +260,7 @@ static bool isBuiltinHeaderName(StringRef FileName) { | |||
.Case("stdarg.h", true) | |||
.Case("stdatomic.h", true) | |||
.Case("stdbool.h", true) | |||
.Case("stdcountof.h", true) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These too!
I've added some modules reviewers, so hopefully they can take a look. Yeah, I agree that tablegen would be a nice thing to have here, but it's a bit odd because the header file itself cannot be table generated. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
For the first commit:
Suggested-by: Alejandro Colomar <alx@kernel.org>
Happy to add it, but for my own education: what's that do? :-D |
Thanks! :)
Quoting that:
|
Ah, it's a Linux kernel thing, that explains why I've not seen it before. Neat idea, thanks! |
WG14 N3469 changed _Lengthof to _Countof but it also introduced the <stdcountof.h> header to expose a macro with a non-ugly identifier. GCC vends this header as part of the compiler implementation, so Clang should do the same.
Suggested-by: Alejandro Colomar alx@kernel.org