"auto" was defined as a keyword back in the K&R days, but as a storage type specifier. No one ever used it, since it was and is the default storage type for local variables.
C++11 recycled the keyword to allow a type to be declared based on the type of an initializer. This was finally adopted into standard C in C23.
gcc and clang provide the "__auto_type" alias keyword as an extension for pre-C23, however, there is no reason to pollute the bulk of the source base with this temporary keyword; instead define "auto" as a macro unless the compiler is running in C23+ mode.
This macro is added in <linux/compiler_types.h> because that header is included in some of the tools headers, wheres <linux/compiler.h> is not as it has a bunch of very kernel-specific things in it.
Changes in v2:
- Restore indentation of macro backslashes (David Laight) - arch/nios2: Replace an adjacent typeof() with a similar "auto" construct (Linus Torvalds) - fs/proc/inode.c: change "__auto_type" to "const auto" (Alexey Dobriyan)
--- arch/nios2/include/asm/uaccess.h | 8 ++++---- arch/x86/include/asm/bug.h | 2 +- arch/x86/include/asm/string_64.h | 6 +++--- arch/x86/include/asm/uaccess_64.h | 2 +- fs/proc/inode.c | 16 ++++++++-------- include/linux/cleanup.h | 6 +++--- include/linux/compiler.h | 2 +- include/linux/compiler_types.h | 13 +++++++++++++ include/linux/minmax.h | 6 +++--- tools/testing/selftests/bpf/prog_tests/socket_helpers.h | 9 +++++++-- tools/virtio/linux/compiler.h | 2 +- 11 files changed, 45 insertions(+), 27 deletions(-)
"auto" was defined as a keyword back in the K&R days, but as a storage type specifier. No one ever used it, since it was and is the default storage type for local variables.
C++11 recycled the keyword to allow a type to be declared based on the type of an initializer. This was finally adopted into standard C in C23.
gcc and clang provide the "__auto_type" alias keyword as an extension for pre-C23, however, there is no reason to pollute the bulk of the source base with this temporary keyword; instead define "auto" as a macro unless the compiler is running in C23+ mode.
This macro is added in <linux/compiler_types.h> because that header is included in some of the tools headers, wheres <linux/compiler.h> is not as it has a bunch of very kernel-specific things in it.
Signed-off-by: H. Peter Anvin (Intel) hpa@zytor.com --- include/linux/compiler_types.h | 13 +++++++++++++ 1 file changed, 13 insertions(+)
diff --git a/include/linux/compiler_types.h b/include/linux/compiler_types.h index 2b77d12e07b2..c8b1ee37934e 100644 --- a/include/linux/compiler_types.h +++ b/include/linux/compiler_types.h @@ -13,6 +13,19 @@
#ifndef __ASSEMBLY__
+/* + * C23 introduces "auto" as a standard way to define type-inferred + * variables, but "auto" has been a (useless) keyword even since K&R C, + * so it has always been "namespace reserved." + * + * Until at some future time we require C23 support, we need the gcc + * extension __auto_type, but there is no reason to put that elsewhere + * in the source code. + */ +#if __STDC_VERSION__ < 202311L +# define auto __auto_type +#endif + /* * Skipped when running bindgen due to a libclang issue; * see https://github.com/rust-lang/rust-bindgen/issues/2244.
On Sun, Jul 20, 2025 at 8:52 AM H. Peter Anvin hpa@zytor.com wrote:
gcc and clang provide the "__auto_type" alias keyword as an extension for pre-C23, however, there is no reason to pollute the bulk of the source base with this temporary keyword; instead define "auto" as a macro unless the compiler is running in C23+ mode.
This macro is added in <linux/compiler_types.h> because that header is included in some of the tools headers, wheres <linux/compiler.h> is not as it has a bunch of very kernel-specific things in it.
Sounds good. I guess we could need a workaround if someone happened to invent an attribute which requires using "auto" in it, since it is not reserved there in C23 AFAIU. So FWIW:
Acked-by: Miguel Ojeda ojeda@kernel.org
- so it has always been "namespace reserved."
Not sure what this means (could we just say reserved?).
Thanks!
Relatedly, there are some proposed, further changes to `auto` for C2y:
https://www.open-std.org/jtc1/sc22/WG14/www/docs/n3579.htm
Cheers, Miguel
Replace instances of "__auto_type" with "auto" in include/linux.
Signed-off-by: H. Peter Anvin (Intel) hpa@zytor.com --- include/linux/cleanup.h | 6 +++--- include/linux/compiler.h | 2 +- include/linux/minmax.h | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/include/linux/cleanup.h b/include/linux/cleanup.h index 7093e1d08af0..c7f3031ae400 100644 --- a/include/linux/cleanup.h +++ b/include/linux/cleanup.h @@ -199,10 +199,10 @@
#define __free(_name) __cleanup(__free_##_name)
-#define __get_and_null(p, nullvalue) \ +#define __get_and_null(p, nullvalue) \ ({ \ - __auto_type __ptr = &(p); \ - __auto_type __val = *__ptr; \ + auto __ptr = &(p); \ + auto __val = *__ptr; \ *__ptr = nullvalue; \ __val; \ }) diff --git a/include/linux/compiler.h b/include/linux/compiler.h index 6f04a1d8c720..7fef5cd41dfc 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -186,7 +186,7 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val, #define data_race(expr) \ ({ \ __kcsan_disable_current(); \ - __auto_type __v = (expr); \ + auto __v = (expr); \ __kcsan_enable_current(); \ __v; \ }) diff --git a/include/linux/minmax.h b/include/linux/minmax.h index eaaf5c008e4d..a0158db54a04 100644 --- a/include/linux/minmax.h +++ b/include/linux/minmax.h @@ -89,7 +89,7 @@ __cmp_once_unique(op, type, x, y, __UNIQUE_ID(x_), __UNIQUE_ID(y_))
#define __careful_cmp_once(op, x, y, ux, uy) ({ \ - __auto_type ux = (x); __auto_type uy = (y); \ + auto ux = (x); auto uy = (y); \ BUILD_BUG_ON_MSG(!__types_ok(ux, uy), \ #op"("#x", "#y") signedness error"); \ __cmp(op, ux, uy); }) @@ -129,7 +129,7 @@ __careful_cmp(max, (x) + 0u + 0ul + 0ull, (y) + 0u + 0ul + 0ull)
#define __careful_op3(op, x, y, z, ux, uy, uz) ({ \ - __auto_type ux = (x); __auto_type uy = (y);__auto_type uz = (z);\ + auto ux = (x); auto uy = (y); auto uz = (z); \ BUILD_BUG_ON_MSG(!__types_ok3(ux, uy, uz), \ #op"3("#x", "#y", "#z") signedness error"); \ __cmp(op, ux, __cmp(op, uy, uz)); }) @@ -203,7 +203,7 @@ * This macro checks @val/@lo/@hi to make sure they have compatible * signedness. */ -#define clamp(val, lo, hi) __careful_clamp(__auto_type, val, lo, hi) +#define clamp(val, lo, hi) __careful_clamp(auto, val, lo, hi)
/** * clamp_t - return a value clamped to a given range using a given type
Replace use of "__auto_type" in fs/proc/inode.c with "const auto".
Suggested-by: Alexey Dobriyan adobriyan@gmail.com Signed-off-by: H. Peter Anvin (Intel) hpa@zytor.com Reviewed-by: Alexey Dobriyan adobriyan@gmail.com --- fs/proc/inode.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/fs/proc/inode.c b/fs/proc/inode.c index 3604b616311c..1afa2dd2285b 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -303,7 +303,7 @@ static ssize_t proc_reg_read_iter(struct kiocb *iocb, struct iov_iter *iter)
static ssize_t pde_read(struct proc_dir_entry *pde, struct file *file, char __user *buf, size_t count, loff_t *ppos) { - __auto_type read = pde->proc_ops->proc_read; + const auto read = pde->proc_ops->proc_read; if (read) return read(file, buf, count, ppos); return -EIO; @@ -325,7 +325,7 @@ static ssize_t proc_reg_read(struct file *file, char __user *buf, size_t count,
static ssize_t pde_write(struct proc_dir_entry *pde, struct file *file, const char __user *buf, size_t count, loff_t *ppos) { - __auto_type write = pde->proc_ops->proc_write; + auto write = pde->proc_ops->proc_write; if (write) return write(file, buf, count, ppos); return -EIO; @@ -347,7 +347,7 @@ static ssize_t proc_reg_write(struct file *file, const char __user *buf, size_t
static __poll_t pde_poll(struct proc_dir_entry *pde, struct file *file, struct poll_table_struct *pts) { - __auto_type poll = pde->proc_ops->proc_poll; + auto poll = pde->proc_ops->proc_poll; if (poll) return poll(file, pts); return DEFAULT_POLLMASK; @@ -369,7 +369,7 @@ static __poll_t proc_reg_poll(struct file *file, struct poll_table_struct *pts)
static long pde_ioctl(struct proc_dir_entry *pde, struct file *file, unsigned int cmd, unsigned long arg) { - __auto_type ioctl = pde->proc_ops->proc_ioctl; + auto ioctl = pde->proc_ops->proc_ioctl; if (ioctl) return ioctl(file, cmd, arg); return -ENOTTY; @@ -392,7 +392,7 @@ static long proc_reg_unlocked_ioctl(struct file *file, unsigned int cmd, unsigne #ifdef CONFIG_COMPAT static long pde_compat_ioctl(struct proc_dir_entry *pde, struct file *file, unsigned int cmd, unsigned long arg) { - __auto_type compat_ioctl = pde->proc_ops->proc_compat_ioctl; + auto compat_ioctl = pde->proc_ops->proc_compat_ioctl; if (compat_ioctl) return compat_ioctl(file, cmd, arg); return -ENOTTY; @@ -414,7 +414,7 @@ static long proc_reg_compat_ioctl(struct file *file, unsigned int cmd, unsigned
static int pde_mmap(struct proc_dir_entry *pde, struct file *file, struct vm_area_struct *vma) { - __auto_type mmap = pde->proc_ops->proc_mmap; + auto mmap = pde->proc_ops->proc_mmap; if (mmap) return mmap(file, vma); return -EIO; @@ -497,7 +497,7 @@ static int proc_reg_open(struct inode *inode, struct file *file) if (!use_pde(pde)) return -ENOENT;
- __auto_type release = pde->proc_ops->proc_release; + auto release = pde->proc_ops->proc_release; if (release) { pdeo = kmem_cache_alloc(pde_opener_cache, GFP_KERNEL); if (!pdeo) { @@ -534,7 +534,7 @@ static int proc_reg_release(struct inode *inode, struct file *file) struct pde_opener *pdeo;
if (pde_is_permanent(pde)) { - __auto_type release = pde->proc_ops->proc_release; + auto release = pde->proc_ops->proc_release; if (release) { return release(inode, file); }
Replace use of "__auto_type" in fs/proc/inode.c with "const auto".
Suggested-by: Alexey Dobriyan adobriyan@gmail.com Signed-off-by: H. Peter Anvin (Intel) hpa@zytor.com Reviewed-by: Alexey Dobriyan adobriyan@gmail.com --- fs/proc/inode.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-)
[ v2 of this patch was an obvious thinko, this is the correct one ]
diff --git a/fs/proc/inode.c b/fs/proc/inode.c index 3604b616311c..8b90ab9b9cfc 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -303,7 +303,7 @@ static ssize_t proc_reg_read_iter(struct kiocb *iocb, struct iov_iter *iter)
static ssize_t pde_read(struct proc_dir_entry *pde, struct file *file, char __user *buf, size_t count, loff_t *ppos) { - __auto_type read = pde->proc_ops->proc_read; + const auto read = pde->proc_ops->proc_read; if (read) return read(file, buf, count, ppos); return -EIO; @@ -325,7 +325,7 @@ static ssize_t proc_reg_read(struct file *file, char __user *buf, size_t count,
static ssize_t pde_write(struct proc_dir_entry *pde, struct file *file, const char __user *buf, size_t count, loff_t *ppos) { - __auto_type write = pde->proc_ops->proc_write; + const auto write = pde->proc_ops->proc_write; if (write) return write(file, buf, count, ppos); return -EIO; @@ -347,7 +347,7 @@ static ssize_t proc_reg_write(struct file *file, const char __user *buf, size_t
static __poll_t pde_poll(struct proc_dir_entry *pde, struct file *file, struct poll_table_struct *pts) { - __auto_type poll = pde->proc_ops->proc_poll; + const auto poll = pde->proc_ops->proc_poll; if (poll) return poll(file, pts); return DEFAULT_POLLMASK; @@ -369,7 +369,7 @@ static __poll_t proc_reg_poll(struct file *file, struct poll_table_struct *pts)
static long pde_ioctl(struct proc_dir_entry *pde, struct file *file, unsigned int cmd, unsigned long arg) { - __auto_type ioctl = pde->proc_ops->proc_ioctl; + const auto ioctl = pde->proc_ops->proc_ioctl; if (ioctl) return ioctl(file, cmd, arg); return -ENOTTY; @@ -392,7 +392,7 @@ static long proc_reg_unlocked_ioctl(struct file *file, unsigned int cmd, unsigne #ifdef CONFIG_COMPAT static long pde_compat_ioctl(struct proc_dir_entry *pde, struct file *file, unsigned int cmd, unsigned long arg) { - __auto_type compat_ioctl = pde->proc_ops->proc_compat_ioctl; + const auto compat_ioctl = pde->proc_ops->proc_compat_ioctl; if (compat_ioctl) return compat_ioctl(file, cmd, arg); return -ENOTTY; @@ -414,7 +414,7 @@ static long proc_reg_compat_ioctl(struct file *file, unsigned int cmd, unsigned
static int pde_mmap(struct proc_dir_entry *pde, struct file *file, struct vm_area_struct *vma) { - __auto_type mmap = pde->proc_ops->proc_mmap; + const auto mmap = pde->proc_ops->proc_mmap; if (mmap) return mmap(file, vma); return -EIO; @@ -497,7 +497,7 @@ static int proc_reg_open(struct inode *inode, struct file *file) if (!use_pde(pde)) return -ENOENT;
- __auto_type release = pde->proc_ops->proc_release; + const auto release = pde->proc_ops->proc_release; if (release) { pdeo = kmem_cache_alloc(pde_opener_cache, GFP_KERNEL); if (!pdeo) { @@ -534,10 +534,9 @@ static int proc_reg_release(struct inode *inode, struct file *file) struct pde_opener *pdeo;
if (pde_is_permanent(pde)) { - __auto_type release = pde->proc_ops->proc_release; - if (release) { + const auto release = pde->proc_ops->proc_release; + if (release) return release(inode, file); - } return 0; }
Replace uses of "__auto_type" in arch/nios2/include/asm/uaccess.h with "auto", and equivalently convert an adjacent cast to the analogous form.
Suggested-by: Linus Torvalds torvalds@linux-foundation.org Signed-off-by: H. Peter Anvin (Intel) hpa@zytor.com --- arch/nios2/include/asm/uaccess.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/arch/nios2/include/asm/uaccess.h b/arch/nios2/include/asm/uaccess.h index b8299082adbe..6ccc9a232c23 100644 --- a/arch/nios2/include/asm/uaccess.h +++ b/arch/nios2/include/asm/uaccess.h @@ -172,15 +172,15 @@ do { \
#define __put_user(x, ptr) \ ({ \ - __auto_type __pu_ptr = (ptr); \ - typeof(*__pu_ptr) __pu_val = (typeof(*__pu_ptr))(x); \ + auto __pu_ptr = (ptr); \ + auto __pu_val = (typeof(*__pu_ptr))(x); \ __put_user_common(__pu_val, __pu_ptr); \ })
#define put_user(x, ptr) \ ({ \ - __auto_type __pu_ptr = (ptr); \ - typeof(*__pu_ptr) __pu_val = (typeof(*__pu_ptr))(x); \ + auto __pu_ptr = (ptr); \ + auto __pu_val = (typeof(*__pu_ptr))(x); \ access_ok(__pu_ptr, sizeof(*__pu_ptr)) ? \ __put_user_common(__pu_val, __pu_ptr) : \ -EFAULT; \
Replace instances of "__auto_type" with "auto" in:
arch/x86/include/asm/bug.h arch/x86/include/asm/string_64.h arch/x86/include/asm/uaccess_64.h
Signed-off-by: H. Peter Anvin (Intel) hpa@zytor.com --- arch/x86/include/asm/bug.h | 2 +- arch/x86/include/asm/string_64.h | 6 +++--- arch/x86/include/asm/uaccess_64.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/arch/x86/include/asm/bug.h b/arch/x86/include/asm/bug.h index f0e9acf72547..05e166faf9a6 100644 --- a/arch/x86/include/asm/bug.h +++ b/arch/x86/include/asm/bug.h @@ -94,7 +94,7 @@ do { \ */ #define __WARN_FLAGS(flags) \ do { \ - __auto_type __flags = BUGFLAG_WARNING|(flags); \ + auto __flags = BUGFLAG_WARNING|(flags); \ instrumentation_begin(); \ _BUG_FLAGS(ASM_UD2, __flags, ANNOTATE_REACHABLE(1b)); \ instrumentation_end(); \ diff --git a/arch/x86/include/asm/string_64.h b/arch/x86/include/asm/string_64.h index 79e9695dc13e..4635616863f5 100644 --- a/arch/x86/include/asm/string_64.h +++ b/arch/x86/include/asm/string_64.h @@ -31,7 +31,7 @@ KCFI_REFERENCE(__memset); #define __HAVE_ARCH_MEMSET16 static inline void *memset16(uint16_t *s, uint16_t v, size_t n) { - const __auto_type s0 = s; + const auto s0 = s; asm volatile ( "rep stosw" : "+D" (s), "+c" (n) @@ -44,7 +44,7 @@ static inline void *memset16(uint16_t *s, uint16_t v, size_t n) #define __HAVE_ARCH_MEMSET32 static inline void *memset32(uint32_t *s, uint32_t v, size_t n) { - const __auto_type s0 = s; + const auto s0 = s; asm volatile ( "rep stosl" : "+D" (s), "+c" (n) @@ -57,7 +57,7 @@ static inline void *memset32(uint32_t *s, uint32_t v, size_t n) #define __HAVE_ARCH_MEMSET64 static inline void *memset64(uint64_t *s, uint64_t v, size_t n) { - const __auto_type s0 = s; + const auto s0 = s; asm volatile ( "rep stosq" : "+D" (s), "+c" (n) diff --git a/arch/x86/include/asm/uaccess_64.h b/arch/x86/include/asm/uaccess_64.h index c8a5ae35c871..b0e4533ce625 100644 --- a/arch/x86/include/asm/uaccess_64.h +++ b/arch/x86/include/asm/uaccess_64.h @@ -72,7 +72,7 @@ static inline void __user *mask_user_address(const void __user *ptr) return ret; } #define masked_user_access_begin(x) ({ \ - __auto_type __masked_ptr = (x); \ + auto __masked_ptr = (x); \ __masked_ptr = mask_user_address(__masked_ptr); \ __uaccess_begin(); __masked_ptr; })
Replace instances of "__auto_type" with "auto" in:
tools/testing/selftests/bpf/prog_tests/socket_helpers.h
This file does not seem to be including <linux/compiler_types.h> directly or indirectly, so copy the definition but guard it with !defined(auto).
Signed-off-by: H. Peter Anvin (Intel) hpa@zytor.com --- tools/testing/selftests/bpf/prog_tests/socket_helpers.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/tools/testing/selftests/bpf/prog_tests/socket_helpers.h b/tools/testing/selftests/bpf/prog_tests/socket_helpers.h index e02cabcc814e..0d59503a0c73 100644 --- a/tools/testing/selftests/bpf/prog_tests/socket_helpers.h +++ b/tools/testing/selftests/bpf/prog_tests/socket_helpers.h @@ -17,11 +17,16 @@ #define VMADDR_CID_LOCAL 1 #endif
+/* include/linux/compiler_types.h */ +#if __STDC_VERSION__ < 202311L && !defined(auto) +# define auto __auto_type +#endif + /* include/linux/cleanup.h */ #define __get_and_null(p, nullvalue) \ ({ \ - __auto_type __ptr = &(p); \ - __auto_type __val = *__ptr; \ + auto __ptr = &(p); \ + auto __val = *__ptr; \ *__ptr = nullvalue; \ __val; \ })
On Sat, 2025-07-19 at 23:50 -0700, H. Peter Anvin wrote:
Replace instances of "__auto_type" with "auto" in:
tools/testing/selftests/bpf/prog_tests/socket_helpers.h
This file does not seem to be including <linux/compiler_types.h> directly or indirectly, so copy the definition but guard it with !defined(auto).
Signed-off-by: H. Peter Anvin (Intel) hpa@zytor.com
Acked-by: Eduard Zingerman eddyz87@gmail.com
[...]
Replace one instance of "__auto_type" with "auto" in:
tools/virtio/linux/compiler.h
This file *does* include <linux/compiler_types.h> directly, so there is no need to duplicate the definition.
Signed-off-by: H. Peter Anvin (Intel) hpa@zytor.com --- tools/virtio/linux/compiler.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/virtio/linux/compiler.h b/tools/virtio/linux/compiler.h index 204ef0e9f542..725b93bfeee1 100644 --- a/tools/virtio/linux/compiler.h +++ b/tools/virtio/linux/compiler.h @@ -31,7 +31,7 @@ */ #define data_race(expr) \ ({ \ - __auto_type __v = (expr); \ + auto __v = (expr); \ __v; \ })
On July 19, 2025 11:50:37 PM PDT, "H. Peter Anvin" hpa@zytor.com wrote:
"auto" was defined as a keyword back in the K&R days, but as a storage type specifier. No one ever used it, since it was and is the default storage type for local variables.
C++11 recycled the keyword to allow a type to be declared based on the type of an initializer. This was finally adopted into standard C in C23.
gcc and clang provide the "__auto_type" alias keyword as an extension for pre-C23, however, there is no reason to pollute the bulk of the source base with this temporary keyword; instead define "auto" as a macro unless the compiler is running in C23+ mode.
Yeah, this is good. We have typeof() used extensively in macros all over. I'll try this for fortify macros and see if we see any binary output changes...
linux-kselftest-mirror@lists.linaro.org