From: Bart Van Assche <bvanassche@acm.org>
To: linux-sparse@vger.kernel.org
Cc: Linus Torvalds <torvalds@linux-foundation.org>,
Bart Van Assche <bvanassche@acm.org>
Subject: [PATCH 60/73] c23: Support storage-class specifiers in compound literals
Date: Mon, 9 Nov 2026 12:32:46 -0800 [thread overview]
Message-ID: <20261109203259.362845-61-bvanassche@acm.org> (raw)
In-Reply-To: <20261109203259.362845-1-bvanassche@acm.org>
Support C23 storage-class specifiers (constexpr, static, register, and
thread_local) in compound literals per ISO C23 6.5.2.5:
- Allow static, register, constexpr, and static thread_local compound
literals while rejecting extern, typedef, auto, file-scope register,
and un-static block-scope thread_local compound literals.
- Keep block-scope constexpr compound literals at automatic storage
duration unless static is also specified, enforce constant initializers
on static and thread_local objects in C23 mode, and warn when taking
the address or decaying an array of a register compound literal.
- Emit anonymous static and thread_local compound literal globals and
their constant scalar or array initializers in sparse-llvm, and warn
under -Wpedantic before C23.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
---
evaluate.c | 28 +++++++--
expand.c | 5 +-
expression.c | 61 ++++++++++++++++---
expression.h | 1 +
parse.c | 59 +++++++++++++-----
sparse-llvm.c | 10 ++-
symbol.h | 4 +-
.../backend/c23-compound-literal-storage.c | 27 ++++++++
.../c23-compound-literal-register-addr.c | 17 ++++++
.../c23-compound-literal-storage-error.c | 37 +++++++++++
.../c23-compound-literal-storage-pedantic.c | 10 +++
validation/c23-compound-literal-storage.c | 27 ++++++++
12 files changed, 252 insertions(+), 34 deletions(-)
create mode 100644 validation/backend/c23-compound-literal-storage.c
create mode 100644 validation/c23-compound-literal-register-addr.c
create mode 100644 validation/c23-compound-literal-storage-error.c
create mode 100644 validation/c23-compound-literal-storage-pedantic.c
create mode 100644 validation/c23-compound-literal-storage.c
diff --git a/evaluate.c b/evaluate.c
index e46b1a7d4f70..32621d04a17e 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -1918,7 +1918,10 @@ static struct symbol *create_pointer(struct expression *expr, struct symbol *sym
access_symbol(sym);
if (sym->ctype.modifiers & MOD_REGISTER) {
- warning(expr->pos, "taking address of 'register' variable '%s'", show_ident(sym->ident));
+ if (sym->ident)
+ warning(expr->pos, "taking address of 'register' variable '%s'", show_ident(sym->ident));
+ else
+ warning(expr->pos, "taking address of 'register' compound literal");
sym->ctype.modifiers &= ~MOD_REGISTER;
}
if (sym->type == SYM_NODE) {
@@ -2944,7 +2947,7 @@ found:
else
v = &top->ident_expression;
- mods |= ctype->ctype.modifiers & (MOD_STORAGE | MOD_CONSTEXPR);
+ mods |= ctype->ctype.modifiers & (MOD_STORAGE | MOD_TLS | MOD_CONSTEXPR);
if (handle_initializer(v, 1, lclass, top->ctype, mods))
continue;
@@ -3236,10 +3239,14 @@ static int handle_initializer(struct expression **ep, int nested,
mods |= ctype->ctype.modifiers;
if (mods & MOD_CONSTEXPR)
check_constexpr_scalar_init(&orig, ctype);
- if ((mods & (MOD_TOPLEVEL | MOD_STATIC)) &&
- !(e->flags & (CEF_ACE | CEF_ADDR)))
- if (Wconstexpr_not_const)
+ else if ((mods & (MOD_TOPLEVEL | MOD_STATIC | MOD_TLS)) &&
+ valid_type(ctype->ctype.base_type) &&
+ !(e->flags & (CEF_ACE | CEF_ADDR))) {
+ if (standard >= STANDARD_C23)
+ sparse_error(e->pos, "non-constant initializer for static object");
+ else if (Wconstexpr_not_const)
warning(e->pos, "non-constant initializer for static object");
+ }
return 1;
}
@@ -3443,13 +3450,22 @@ static struct symbol *evaluate_compound_literal(struct expression *expr, struct
addr->ctype = &lazy_ptr_ctype; /* Lazy eval */
addr->symbol = sym;
- if (sym->ctype.modifiers & MOD_TOPLEVEL)
+ if (sym->ctype.modifiers & (MOD_TOPLEVEL | MOD_STATIC | MOD_TLS))
addr->flags |= CEF_ADDR;
expr->type = EXPR_PREOP;
expr->op = '*';
expr->deref = addr;
expr->ctype = sym;
+ if (sym->ctype.modifiers & MOD_CONSTEXPR) {
+ struct symbol *base_type = get_base_type(sym);
+ if (is_float_type(base_type))
+ expr->flags = CEF_SET_FLOAT;
+ else if (is_int_type(base_type))
+ expr->flags = CEF_SET_ICE;
+ else
+ expr->flags = CEF_ADDR;
+ }
return sym;
}
diff --git a/expand.c b/expand.c
index 13a3bc0457ba..7c85b66ab02f 100644
--- a/expand.c
+++ b/expand.c
@@ -848,9 +848,8 @@ static int expand_dereference(struct expression *expr)
expr->type = EXPR_VALUE;
expr->value = value->value;
expr->taint = 0;
- if ((sym->ctype.modifiers & MOD_CONSTEXPR) &&
- is_int_type(ctype))
- expr->flags = CEF_SET_ICE;
+ if (sym->ctype.modifiers & MOD_CONSTEXPR)
+ expr->flags = is_int_type(ctype) ? CEF_SET_ICE : CEF_ADDR;
return 0;
} else if (value->type == EXPR_FVALUE) {
if (!is_float_type(ctype))
diff --git a/expression.c b/expression.c
index ace0bf6d1a31..65efff3b61fe 100644
--- a/expression.c
+++ b/expression.c
@@ -150,6 +150,7 @@ static struct token *parse_type(struct token *token, struct expression **tree)
struct symbol *sym;
*tree = alloc_expression(token->pos, EXPR_TYPE);
token = typename(token, &sym, NULL);
+ check_typename_storage(sym);
if (sym->ident)
sparse_error(token->pos,
"type expression should not include identifier "
@@ -198,6 +199,7 @@ static struct token *builtin_offsetof_expr(struct token *token,
token = token->next;
token = typename(token, &sym, NULL);
+ check_typename_storage(sym);
if (sym->ident)
sparse_error(token->pos,
"type expression should not include identifier "
@@ -569,6 +571,7 @@ static struct token *generic_selection(struct token *token, struct expression **
if (lookup_type(token)) {
struct type_expression *map = __alloc_type_expression(0);
token = typename(token, &map->type, NULL);
+ check_typename_storage(map->type);
token = expect(token, ':', "after typename");
token = assignment_expression(token, &map->expr);
if (!map->expr)
@@ -730,6 +733,7 @@ struct token *primary_expression(struct token *token, struct expression **tree)
if (token->special == '[' && lookup_type(token->next)) {
expr = alloc_expression(token->pos, EXPR_TYPE);
token = typename(token->next, &expr->symbol, NULL);
+ check_typename_storage(expr->symbol);
token = expect(token, ']', "in type expression");
break;
}
@@ -837,6 +841,46 @@ static struct token *postfix_expression(struct token *token, struct expression *
static struct token *cast_expression(struct token *token, struct expression **tree);
static struct token *unary_expression(struct token *token, struct expression **tree);
+static void check_compound_literal_storage(struct symbol *sym, int is_force)
+{
+ unsigned long mods;
+
+ if (toplevel(block_scope))
+ sym->ctype.modifiers |= MOD_TOPLEVEL;
+ if (is_force)
+ warning(sym->pos, "[force] in compound literal");
+ mods = sym->ctype.modifiers;
+ if (mods & MOD_EXTERN) {
+ sparse_error(sym->pos, "'extern' is not allowed in compound literal");
+ return;
+ }
+ if (sym->explicit_typedef) {
+ sparse_error(sym->pos, "'typedef' is not allowed in compound literal");
+ return;
+ }
+ if ((mods & MOD_AUTO) || sym->ctype.base_type == &autotype_ctype) {
+ sparse_error(sym->pos, "'auto' is not allowed in compound literal");
+ if (sym->ctype.base_type == &autotype_ctype)
+ sym->ctype.base_type = &int_ctype;
+ return;
+ }
+ if ((mods & MOD_TOPLEVEL) && (mods & MOD_REGISTER)) {
+ sparse_error(sym->pos,
+ "file-scope compound literal cannot specify 'register'");
+ return;
+ }
+ if (!(mods & MOD_TOPLEVEL) && (mods & MOD_TLS) && !(mods & MOD_STATIC)) {
+ sparse_error(sym->pos,
+ "block-scope compound literal with 'thread_local' requires 'static'");
+ return;
+ }
+ if (mods & (MOD_STATIC | MOD_REGISTER | MOD_TLS | MOD_CONSTEXPR)) {
+ if (standard < STANDARD_C23 && Wpedantic)
+ warning(sym->pos,
+ "storage-class specifiers in compound literals are a C23 feature");
+ }
+}
+
static struct token *type_info_expression(struct token *token,
struct expression **tree, int type)
{
@@ -845,6 +889,7 @@ static struct token *type_info_expression(struct token *token,
bool std_alignof = (op_ident == &_Alignof_ident ||
op_ident == &alignof_ident);
struct token *p;
+ int is_force = 0;
*tree = expr;
expr->flags = CEF_SET_ICE; /* XXX: VLA support will need that changed */
@@ -857,7 +902,7 @@ static struct token *type_info_expression(struct token *token,
return unary_expression(token, &expr->cast_expression);
}
p = token;
- token = typename(token->next, &expr->cast_type, NULL);
+ token = typename(token->next, &expr->cast_type, &is_force);
if (!match_op(token, ')')) {
static const char * error[] = {
@@ -865,6 +910,7 @@ static struct token *type_info_expression(struct token *token,
[EXPR_ALIGNOF] = "at end of __alignof__",
[EXPR_PTRSIZEOF] = "at end of __sizeof_ptr__"
};
+ check_typename_storage(expr->cast_type);
return expect(token, ')', error[type]);
}
@@ -874,16 +920,20 @@ static struct token *type_info_expression(struct token *token,
* of a typed initializer expression..
*/
if (match_op(token, '{')) {
+ struct symbol *sym = expr->cast_type;
struct expression *cast = alloc_expression(p->pos, EXPR_CAST);
if (std_alignof && Wpedantic)
warning(expr->pos,
"ISO C does not allow '%s' on an expression",
show_ident(op_ident));
- cast->cast_type = expr->cast_type;
+ check_compound_literal_storage(sym, is_force);
+ cast->cast_type = sym;
expr->cast_type = NULL;
expr->cast_expression = cast;
token = initializer(&cast->cast_expression, token);
token = postfix_expression(token, &expr->cast_expression, cast);
+ } else {
+ check_typename_storage(expr->cast_type);
}
return token;
}
@@ -993,14 +1043,11 @@ static struct token *cast_expression(struct token *token, struct expression **tr
cast->cast_type = sym;
token = expect(token, ')', "at end of cast operator");
if (match_op(token, '{')) {
- if (toplevel(block_scope))
- sym->ctype.modifiers |= MOD_TOPLEVEL;
- if (is_force)
- warning(sym->pos,
- "[force] in compound literal");
+ check_compound_literal_storage(sym, is_force);
token = initializer(&cast->cast_expression, token);
return postfix_expression(token, tree, cast);
}
+ check_typename_storage(sym);
*tree = cast;
if (is_force)
cast->type = EXPR_FORCE_CAST;
diff --git a/expression.h b/expression.h
index 8c387adf9d5b..213c31d246aa 100644
--- a/expression.h
+++ b/expression.h
@@ -319,6 +319,7 @@ static inline struct expression *alloc_const_expression(struct position pos, int
/* Type name parsing */
struct token *typename(struct token *, struct symbol **, int *);
+void check_typename_storage(struct symbol *sym);
static inline int lookup_type(struct token *token)
{
diff --git a/parse.c b/parse.c
index 782683a84fba..0787ad2af576 100644
--- a/parse.c
+++ b/parse.c
@@ -840,6 +840,7 @@ static struct token *struct_union_enum_specifier(enum type type,
warning(token->pos,
"ISO C does not support specifying 'enum' underlying types before C23");
token = typename(token->next, &underlying, NULL);
+ check_typename_storage(underlying);
underlying = examine_symbol_type(underlying);
if (!underlying || !is_int_type(underlying) ||
is_enum_type(underlying)) {
@@ -923,6 +924,7 @@ static struct token *struct_union_enum_specifier(enum type type,
warning(token->pos,
"ISO C does not support specifying 'enum' underlying types before C23");
token = typename(token->next, &underlying, NULL);
+ check_typename_storage(underlying);
underlying = examine_symbol_type(underlying);
if (!underlying || !is_int_type(underlying) ||
is_enum_type(underlying)) {
@@ -1337,6 +1339,7 @@ static struct token *typeof_specifier_helper(struct token *token, struct symbol
if (lookup_type(token->next)) {
struct symbol *sym;
token = typename(token->next, &sym, NULL);
+ check_typename_storage(sym);
sym = examine_symbol_type(sym);
if (!qual) {
sym->ctype.modifiers &= ~MOD_QUALIFIER;
@@ -1780,6 +1783,7 @@ static struct token *alignas_specifier(struct token *token, struct symbol *sym,
if (lookup_type(token->next)) {
struct symbol *sym = NULL;
token = typename(token->next, &sym, NULL);
+ check_typename_storage(sym);
sym = examine_symbol_type(sym);
alignment = sym->ctype.alignment;
token = expect(token, ')', "after _Alignas(...");
@@ -2550,37 +2554,62 @@ static struct token *parameter_declaration(struct token *token, struct symbol *s
return token;
}
-struct token *typename(struct token *token, struct symbol **p, int *forced)
+void check_typename_storage(struct symbol *sym)
{
- struct decl_state ctx = {.prefer_abstract = 1};
+ struct symbol *base;
unsigned long class;
+ if (!sym)
+ return;
+ for (base = sym; base && (base->type == SYM_NODE ||
+ base->type == SYM_PTR ||
+ base->type == SYM_ARRAY);
+ base = base->ctype.base_type)
+ ;
+ if (base == &autotype_ctype) {
+ sparse_error(sym->pos, "'%s' in type name",
+ sym->c23_auto ? "auto" : "__auto_type");
+ sym->ctype.base_type = &bad_ctype;
+ return;
+ }
+ if (sym->has_alignas)
+ sparse_error(sym->pos, "alignment specified for type name");
+ if (sym->ctype.modifiers & MOD_CONSTEXPR)
+ sparse_error(sym->pos, "constexpr in typename");
+ class = sym->ctype.modifiers & (MOD_STORAGE | MOD_TLS);
+ if (class)
+ warning(sym->pos, "storage class in typename (%s%s)",
+ modifier_string(class), show_typename(sym));
+}
+
+struct token *typename(struct token *token, struct symbol **p, int *forced)
+{
+ struct decl_state ctx = { .prefer_abstract = 1 };
struct symbol *sym = alloc_symbol(token->pos, SYM_NODE);
+ unsigned long mod;
*p = sym;
token = declaration_specifiers(token, &ctx);
- if (ctx.has_alignas)
- sparse_error(sym->pos, "alignment specified for type name");
+ mod = decl_modifiers(&ctx);
if (ctx.opaque_fixed_enum)
sparse_error(ctx.opaque_fixed_enum_pos,
"'enum' underlying type may not be specified here");
- if (ctx.autotype) {
- sparse_error(sym->pos, "'%s' in type name",
- ctx.has_auto ? "auto" : "__auto_type");
- ctx.ctype.base_type = &bad_ctype;
- }
token = declarator(token, &ctx);
token = handle_attributes(token, &ctx);
ctx.ctype.modifiers |= ctx.ident_modifiers;
apply_modifiers(token->pos, &ctx);
sym->ctype = ctx.ctype;
+ sym->c23_auto = ctx.autotype && ctx.has_auto;
sym->endpos = token->pos;
- if (ctx.is_constexpr)
- sparse_error(sym->pos, "constexpr in typename");
- class = ctx.storage_class;
+ if (ctx.storage_class == MOD_USERTYPE)
+ sym->explicit_typedef = 1;
+ if (ctx.has_alignas)
+ sym->has_alignas = 1;
+ if (ctx.is_constexpr) {
+ apply_constexpr_const(sym);
+ sym->ctype.modifiers |= MOD_CONSTEXPR;
+ }
+ sym->ctype.modifiers |= mod | decl_modifiers(&ctx);
if (forced)
*forced = ctx.forced;
- if (class)
- warning(sym->pos, "storage class in typename (%s%s)",
- modifier_string(class), show_typename(sym));
return token;
}
diff --git a/sparse-llvm.c b/sparse-llvm.c
index f3f6b7e01171..7d15d7a70e54 100644
--- a/sparse-llvm.c
+++ b/sparse-llvm.c
@@ -318,7 +318,7 @@ static LLVMValueRef get_sym_value(LLVMModuleRef module, struct symbol *sym)
LLVMValueRef result = NULL;
struct expression *expr;
- assert(sym->bb_target == NULL);
+ assert(sym->namespace != NS_LABEL);
expr = sym->initializer;
if (expr && !sym->ident) {
@@ -348,6 +348,14 @@ static LLVMValueRef get_sym_value(LLVMModuleRef module, struct symbol *sym)
}
}
+ if (!sym->ident && (sym->ctype.modifiers & (MOD_STATIC | MOD_TOPLEVEL | MOD_TLS))) {
+ if (!sym->aux) {
+ expand_symbol(sym);
+ sym->aux = output_data(module, sym);
+ }
+ return sym->aux;
+ }
+
if (LLVMGetTypeKind(type) == LLVMFunctionTypeKind) {
result = LLVMGetNamedFunction(module, name);
if (!result)
diff --git a/symbol.h b/symbol.h
index 942baad97df5..435fa18a4990 100644
--- a/symbol.h
+++ b/symbol.h
@@ -196,7 +196,7 @@ struct symbol {
designated_init : 1, forced_arg : 1,
accessed : 1, builtin : 1, torename : 1,
packed : 1, transparent_union : 1,
- fixed_type : 1;
+ fixed_type : 1, explicit_typedef : 1;
unsigned int has_alignas : 1;
unsigned int kr_args : 1;
unsigned int underspecified : 1;
@@ -282,7 +282,7 @@ struct symbol {
/* like cvr-qualifiers but 'reversed' (OK: source <= target) */
#define MOD_REV_QUAL (MOD_PURE|MOD_NORETURN)
/* do not warn when these are duplicated */
-#define MOD_DUP_OK (MOD_UNUSED|MOD_GNU_INLINE)
+#define MOD_DUP_OK (MOD_UNUSED|MOD_GNU_INLINE|MOD_USERTYPE)
/* must be part of the declared symbol, not its type */
#define MOD_DECLARE \
(MOD_STORAGE | MOD_INLINE | MOD_TLS | MOD_GNU_INLINE | MOD_UNUSED | \
diff --git a/validation/backend/c23-compound-literal-storage.c b/validation/backend/c23-compound-literal-storage.c
new file mode 100644
index 000000000000..e4f0d430e6c8
--- /dev/null
+++ b/validation/backend/c23-compound-literal-storage.c
@@ -0,0 +1,27 @@
+static const int *g_arr = (static int[]){ 1, 2, 3 };
+
+int *test_cl_static_scalar_addr(void);
+int *test_cl_static_scalar_addr(void)
+{
+ return &(static int){ 42 };
+}
+
+int test_cl_llvm(void);
+int test_cl_llvm(void)
+{
+ int *lp = (static int[]){ 7, 8, 9 };
+ int *tp = (static thread_local int[]){ 14 };
+ register int rv = (register int){ 12 };
+ int ce = (constexpr int){ 42 };
+
+ lp[0] += 1;
+ return g_arr[0] + lp[0] + tp[0] + rv + ce;
+}
+
+/*
+ * check-name: backend-c23-compound-literal-storage
+ * check-command: sparse-llvm-dis -m64 -std=c23 $file
+ * check-output-ignore
+ * check-output-contains: private global i32 42
+ * check-output-contains: define i32 @test_cl_llvm(
+ */
diff --git a/validation/c23-compound-literal-register-addr.c b/validation/c23-compound-literal-register-addr.c
new file mode 100644
index 000000000000..0bd817efcc6a
--- /dev/null
+++ b/validation/c23-compound-literal-register-addr.c
@@ -0,0 +1,17 @@
+static void bad_reg_addr(void)
+{
+ int *p = &(register int){ 1 };
+ int *q = (register int[]){ 1, 2 };
+ (void)p;
+ (void)q;
+}
+
+/*
+ * check-name: c23-compound-literal-register-addr
+ * check-command: sparse -std=c23 $file
+ *
+ * check-error-start
+c23-compound-literal-register-addr.c:3:20: warning: taking address of 'register' compound literal
+c23-compound-literal-register-addr.c:4:19: warning: taking address of 'register' compound literal
+ * check-error-end
+ */
diff --git a/validation/c23-compound-literal-storage-error.c b/validation/c23-compound-literal-storage-error.c
new file mode 100644
index 000000000000..c6bf45d7cb1d
--- /dev/null
+++ b/validation/c23-compound-literal-storage-error.c
@@ -0,0 +1,37 @@
+void *e = (extern int[]){ 1 };
+void *t = (typedef int[]){ 1 };
+int f_reg = sizeof((register int){ 1 });
+
+static void bad_block_literals(int non_const)
+{
+ int *a1 = (auto int[]){ 1, 2 };
+ int a2 = (auto){ 1 };
+ int *tl = (thread_local int[]){ 14 };
+ int *nc = (static int[]){ non_const };
+ int *dup_s = (static static int[]){ 1 };
+ int s_reg = (static register int){ 1 };
+
+ (void)a1;
+ (void)a2;
+ (void)tl;
+ (void)nc;
+ (void)dup_s;
+ (void)s_reg;
+}
+
+/*
+ * check-name: c23-compound-literal-storage-error
+ * check-command: sparse -std=c23 -Wno-decl $file
+ *
+ * check-error-start
+c23-compound-literal-storage-error.c:1:12: error: 'extern' is not allowed in compound literal
+c23-compound-literal-storage-error.c:2:12: error: 'typedef' is not allowed in compound literal
+c23-compound-literal-storage-error.c:3:21: error: file-scope compound literal cannot specify 'register'
+c23-compound-literal-storage-error.c:7:20: error: 'auto' is not allowed in compound literal
+c23-compound-literal-storage-error.c:8:19: error: 'auto' is not allowed in compound literal
+c23-compound-literal-storage-error.c:9:20: error: block-scope compound literal with 'thread_local' requires 'static'
+c23-compound-literal-storage-error.c:11:37: error: duplicate static
+c23-compound-literal-storage-error.c:12:38: error: multiple storage classes
+c23-compound-literal-storage-error.c:10:35: error: non-constant initializer for static object
+ * check-error-end
+ */
diff --git a/validation/c23-compound-literal-storage-pedantic.c b/validation/c23-compound-literal-storage-pedantic.c
new file mode 100644
index 000000000000..a4ddc95fdb0f
--- /dev/null
+++ b/validation/c23-compound-literal-storage-pedantic.c
@@ -0,0 +1,10 @@
+static const int *p = (static int[]){ 1, 2, 3 };
+
+/*
+ * check-name: c23-compound-literal-storage-pedantic
+ * check-command: sparse -std=c11 -Wpedantic $file
+ *
+ * check-error-start
+c23-compound-literal-storage-pedantic.c:1:24: warning: storage-class specifiers in compound literals are a C23 feature
+ * check-error-end
+ */
diff --git a/validation/c23-compound-literal-storage.c b/validation/c23-compound-literal-storage.c
new file mode 100644
index 000000000000..75a4552eecde
--- /dev/null
+++ b/validation/c23-compound-literal-storage.c
@@ -0,0 +1,27 @@
+static const int *p = (static int[]){ 1, 2, 3 };
+static const int *cp = (constexpr int[]){ 4, 5, 6 };
+
+static int test(void)
+{
+ static int *lp = (static int[]){ 7, 8, 9 };
+ register int rv = (register int){ 12 };
+ int *tp = (static thread_local int[]){ 14 };
+ const int *lcp = &(static constexpr int){ 99 };
+ int auto_ce = (constexpr int){ 42 };
+
+ return lp[0] + rv + tp[0] + *lcp + auto_ce + p[0] + cp[0];
+}
+
+static_assert(sizeof((static int[]){ 1, 2, 3 }) == 3 * sizeof(int),
+ "sizeof static compound literal");
+static_assert(sizeof((constexpr int[]){ 1, 2, 3, 4 }) == 4 * sizeof(int),
+ "sizeof constexpr compound literal");
+static_assert(sizeof((thread_local int[]){ 14, 15 }) == 2 * sizeof(int),
+ "sizeof file-scope thread_local compound literal");
+static_assert((constexpr int){ 42 } == 42,
+ "constexpr scalar compound literal in ICE");
+
+/*
+ * check-name: c23-compound-literal-storage
+ * check-command: sparse -std=c23 -pedantic $file
+ */
next prev parent reply other threads:[~2026-11-09 20:33 UTC|newest]
Thread overview: 74+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-09 20:31 Bart Van Assche
2026-11-09 20:31 ` [PATCH 01/73] Makefile: Pass '--' to rm in clean target to handle dash-prefixed files Bart Van Assche
2026-11-09 20:31 ` [PATCH 02/73] sparse-llvm: Use LLVMCreateBuilderForModule() with LLVM 24 and later Bart Van Assche
2026-11-09 20:31 ` [PATCH 03/73] typeof_unqual: Strip qualifiers and address space from types and arrays Bart Van Assche
2026-11-09 20:31 ` [PATCH 04/73] bitfield: Pack consecutive _Bool bitfields into byte containers Bart Van Assche
2026-11-09 20:31 ` [PATCH 05/73] allocate: Harden slab allocation bounds, zeroing, and mmap checks Bart Van Assche
2026-11-09 20:31 ` [PATCH 06/73] tokenize: Support 4096-byte identifiers and fix escape bounds Bart Van Assche
2026-11-09 20:31 ` [PATCH 07/73] pre-process: Fix macro expansion and include directive handling Bart Van Assche
2026-11-09 20:31 ` [PATCH 08/73] options, lib: Harden warning buffers and command-line option parsing Bart Van Assche
2026-11-09 20:31 ` [PATCH 09/73] builtin: Fix atomic builtin type checking and object_size bounds Bart Van Assche
2026-11-09 20:31 ` [PATCH 10/73] parse, show-parse: Fix attribute propagation, enum overflow, and bounds Bart Van Assche
2026-11-09 20:31 ` [PATCH 11/73] target-openrisc: Set target_openrisc.mach to MACH_OPENRISC Bart Van Assche
2026-11-09 20:31 ` [PATCH 12/73] evaluate: Fix pointer arithmetic, incomplete types, and qualifiers Bart Van Assche
2026-11-09 20:31 ` [PATCH 13/73] expand: Fix static initializer folding and floating-point casts Bart Van Assche
2026-11-09 20:32 ` [PATCH 14/73] inline: Copy union cast types and VLA bounds when inlining Bart Van Assche
2026-11-09 20:32 ` [PATCH 15/73] linearize, flow: Fix asm operands, switch case bounds, and DSE Bart Van Assche
2026-11-09 20:32 ` [PATCH 16/73] memops, ssa: Walk parent insns in reverse and skip mixed-size SSA Bart Van Assche
2026-11-09 20:32 ` [PATCH 17/73] simplify: Prevent overflow on LLONG_MIN negation and fix simplifications Bart Van Assche
2026-11-09 20:32 ` [PATCH 18/73] sparse: Gate context failure warning on Wcontext and catch underflow Bart Van Assche
2026-11-09 20:32 ` [PATCH 19/73] ast-model: Return AST_N_COLUMNS and inspect child nodes lazily Bart Van Assche
2026-11-09 20:32 ` [PATCH 20/73] c2xml: Guard against recursive symbols and free xmlGetProp() string Bart Van Assche
2026-11-09 20:32 ` [PATCH 21/73] compile-i386: Fix buffer bounds, unsigned '<=' codegen, and null checks Bart Van Assche
2026-11-09 20:32 ` [PATCH 22/73] ctags: Fix line comparison order and handle SYM_RESTRICT and SYM_LABEL Bart Van Assche
2026-11-09 20:32 ` [PATCH 23/73] dissect: Unwrap array element type via base_type() Bart Van Assche
2026-11-09 20:32 ` [PATCH 24/73] example: Fix show_op() rotating buffer dimensions Bart Van Assche
2026-11-09 20:32 ` [PATCH 25/73] graph: Check PSEUDO_SYM before dereferencing insn->func->sym Bart Van Assche
2026-11-09 20:32 ` [PATCH 26/73] scheck: Fix slice() upper bit index calculation Bart Van Assche
2026-11-09 20:32 ` [PATCH 27/73] sparse-llvm: Support arbitrary struct member counts and fix operand types Bart Van Assche
2026-11-09 20:32 ` [PATCH 28/73] inline: Duplicate generic expressions instead of evaluating them Bart Van Assche
2026-11-09 20:32 ` [PATCH 29/73] lib: Avoid mutating fmt before va_start() in warning() Bart Van Assche
2026-11-09 20:32 ` [PATCH 30/73] cse, canon: Cast pointers to uintptr_t before relational comparison Bart Van Assche
2026-11-09 20:32 ` [PATCH 31/73] context: Add "conditional context increment" model Bart Van Assche
2026-11-09 20:32 ` [PATCH 32/73] expand: Simplify signed constants early Bart Van Assche
2026-11-09 20:32 ` [PATCH 33/73] bitwise: Allow all-bits-set as a restricted value Bart Van Assche
2026-11-09 20:32 ` [PATCH 34/73] bitwise: Allow restricted ordered compares with unrestricted values Bart Van Assche
2026-11-09 20:32 ` [PATCH 35/73] bitwise: Keep unrestricted values unrestricted after a cast Bart Van Assche
2026-11-09 20:32 ` [PATCH 36/73] bitwise: Don't remove MOD_SPECIFIER from 'bitwise' types Bart Van Assche
2026-11-09 20:32 ` [PATCH 37/73] bitwise: Allow both regular casts and forced casts for restricted values Bart Van Assche
2026-11-09 20:32 ` [PATCH 38/73] clang-format: Add .clang-format configuration file Bart Van Assche
2026-11-09 20:32 ` [PATCH 39/73] options: Add support for -std=c23, -std=c2x and -std=gnu23 Bart Van Assche
2026-11-09 20:32 ` [PATCH 40/73] preprocessor: Add support for #elifdef and #elifndef Bart Van Assche
2026-11-09 20:32 ` [PATCH 41/73] preprocessor: Add support for __has_include and __has_include_next Bart Van Assche
2026-11-09 20:32 ` [PATCH 42/73] c23: Add support for static_assert, alignas, alignof, thread_local Bart Van Assche
2026-11-09 20:32 ` [PATCH 43/73] c23: Add support for bool, true, and false keywords Bart Van Assche
2026-11-09 20:32 ` [PATCH 44/73] c23: Add support for nullptr and nullptr_t Bart Van Assche
2026-11-09 20:32 ` [PATCH 45/73] c23: Add support for digit separators in numeric literals Bart Van Assche
2026-11-09 20:32 ` [PATCH 46/73] c23: Support unnamed parameters in function definitions Bart Van Assche
2026-11-09 20:32 ` [PATCH 47/73] c23: Support variadic functions without named parameters Bart Van Assche
2026-11-09 20:32 ` [PATCH 48/73] c23: Support labels before declarations and at block ends Bart Van Assche
2026-11-09 20:32 ` [PATCH 49/73] c23: Support auto type inference Bart Van Assche
2026-11-09 20:32 ` [PATCH 50/73] c23: Support constexpr object specifier Bart Van Assche
2026-11-09 20:32 ` [PATCH 51/73] c23: Support enumerations with fixed underlying types Bart Van Assche
2026-11-09 20:32 ` [PATCH 52/73] c23: Support standard [[]] attribute syntax Bart Van Assche
2026-11-09 20:32 ` [PATCH 53/73] preprocessor: Add support for __has_c_attribute Bart Van Assche
2026-11-09 20:32 ` [PATCH 54/73] c23: Support empty initializer braces {} Bart Van Assche
2026-11-09 20:32 ` [PATCH 55/73] preprocessor: Add support for __has_embed Bart Van Assche
2026-11-09 20:32 ` [PATCH 56/73] preprocessor: Add support for #embed directive Bart Van Assche
2026-11-09 20:32 ` [PATCH 57/73] c23: Add support for u8 character constants and string literals Bart Van Assche
2026-11-09 20:32 ` [PATCH 58/73] preprocessor: Add support for __VA_OPT__ Bart Van Assche
2026-11-09 20:32 ` [PATCH 59/73] c23: Treat empty parameter list () as (void) and reject K&R functions Bart Van Assche
2026-11-09 20:32 ` Bart Van Assche [this message]
2026-11-09 20:32 ` [PATCH 61/73] c23: Add support for _BitInt(N) Bart Van Assche
2026-11-09 20:32 ` [PATCH 62/73] enum: Support machine mode attributes on enumeration types Bart Van Assche
2026-11-09 20:32 ` [PATCH 63/73] enum: Support __attribute__((packed)) " Bart Van Assche
2026-11-09 20:32 ` [PATCH 64/73] expand: Ignore top-level non-array address space in compare_types() Bart Van Assche
2026-11-09 20:32 ` [PATCH 65/73] builtin: Support __builtin_infer_alloc_token() as a size_t ICE Bart Van Assche
2026-11-09 20:32 ` [PATCH 66/73] builtin: Add support for Linux kernel compiler builtins Bart Van Assche
2026-11-09 20:32 ` [PATCH 67/73] builtin: Add support for __builtin_has_attribute() Bart Van Assche
2026-11-09 20:32 ` [PATCH 68/73] cleanup: Support __attribute__((cleanup(...))) in linearize and -Wcontext Bart Van Assche
2026-11-09 20:32 ` [PATCH 69/73] builtin: Do not evaluate __builtin_clz(0) and __builtin_ctz(0) Bart Van Assche
2026-11-09 20:32 ` [PATCH 70/73] pre-process: Support long token and string expansions dynamically Bart Van Assche
2026-11-09 20:32 ` [PATCH 71/73] x86: Undefine conflicting bitness macros when parsing -m flags Bart Van Assche
2026-11-09 20:32 ` [PATCH 72/73] evaluate: Accept conditional expressions with only one void side Bart Van Assche
2026-11-09 20:32 ` [PATCH 73/73] ci: Add Linux kernel GitHub Actions workflow and build script Bart Van Assche
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261109203259.362845-61-bvanassche@acm.org \
--to=bvanassche@acm.org \
--cc=linux-sparse@vger.kernel.org \
--cc=torvalds@linux-foundation.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox