https://github.com/a-tarasyuk created https://github.com/llvm/llvm-project/pull/182770
Fixes #178349 --- This patch resolves an issue where accessing C23 `constexpr` struct members using the dot operator was not recognized as a constant expression. According to C23 spec: > 6.6p7: > > An identifier that is: > — an enumeration constant, > — a predefined constant, or > — declared with storage-class specifier constexpr and has an object type, > is a named constant, as is a postfix expression that applies the . member > access operator to a named > constant of structure or union type, even recursively. For enumeration and > predefined constants, > their value and type are defined in the respective clauses; for constexpr > objects, such a named > constant is a constant expression with the type and value of the declared > object. > > § 6.6p13: > > A structure or union constant is a named constant or compound literal > constant with structure or > union type, respectively > > § 6.6p15: > > Starting from a structure or union constant, the member-access . operator may > be used to form a > named constant or compound literal constant as described previously in this > subclause >From 5b51c2654d2bb8f859ff3fa61efb9ce2a00563a7 Mon Sep 17 00:00:00 2001 From: Oleksandr Tarasiuk <[email protected]> Date: Sun, 22 Feb 2026 18:23:55 +0200 Subject: [PATCH] [Clang] support C23 constexpr struct member access in constant expressions --- clang/docs/ReleaseNotes.rst | 1 + clang/lib/AST/ExprConstant.cpp | 21 ++++++++- clang/test/C/drs/dr4xx.c | 2 +- clang/test/Sema/constexpr-member-access.c | 54 +++++++++++++++++++++++ 4 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 clang/test/Sema/constexpr-member-access.c diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 6e9e5baea2921..ed555627977ee 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -130,6 +130,7 @@ C2y Feature Support C23 Feature Support ^^^^^^^^^^^^^^^^^^^ +- Clang now allows C23 ``constexpr`` struct member access through the dot operator in constant expressions. (#GH178349) Non-comprehensive list of changes in this release ------------------------------------------------- diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 2c13befec02f2..c249624ff4cda 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -21009,7 +21009,6 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) { case Expr::ArraySectionExprClass: case Expr::OMPArrayShapingExprClass: case Expr::OMPIteratorExprClass: - case Expr::MemberExprClass: case Expr::CompoundAssignOperatorClass: case Expr::CompoundLiteralExprClass: case Expr::ExtVectorElementExprClass: @@ -21087,6 +21086,26 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) { case Expr::HLSLOutArgExprClass: return ICEDiag(IK_NotICE, E->getBeginLoc()); + case Expr::MemberExprClass: { + if (Ctx.getLangOpts().C23) { + const Expr *ME = E->IgnoreParenImpCasts(); + while (const auto *M = dyn_cast<MemberExpr>(ME)) { + if (M->isArrow()) + return ICEDiag(IK_NotICE, E->getBeginLoc()); + ME = M->getBase()->IgnoreParenImpCasts(); + } + const auto *DRE = dyn_cast<DeclRefExpr>(ME); + if (DRE) { + const auto *VD = dyn_cast<VarDecl>(DRE->getDecl()); + if (VD && VD->isConstexpr()) + return CheckEvalInICE(E, Ctx); + } + if (isa<CompoundLiteralExpr>(ME)) + return CheckEvalInICE(E, Ctx); + } + return ICEDiag(IK_NotICE, E->getBeginLoc()); + } + case Expr::InitListExprClass: { // C++03 [dcl.init]p13: If T is a scalar type, then a declaration of the // form "T x = { a };" is equivalent to "T x = a;". diff --git a/clang/test/C/drs/dr4xx.c b/clang/test/C/drs/dr4xx.c index 83d7b94cd6795..fda5e437b8759 100644 --- a/clang/test/C/drs/dr4xx.c +++ b/clang/test/C/drs/dr4xx.c @@ -106,7 +106,7 @@ void dr413(void) { * not 0. */ _Static_assert((S){ /* c89only-warning {{compound literals are a C99-specific feature}} - expected-warning {{expression is not an integer constant expression; folding it to a constant is a GNU extension}} + pre-c23-warning {{expression is not an integer constant expression; folding it to a constant is a GNU extension}} */ 1, .t = { /* c89only-warning {{designated initializers are a C99 feature}} */ diff --git a/clang/test/Sema/constexpr-member-access.c b/clang/test/Sema/constexpr-member-access.c new file mode 100644 index 0000000000000..a2cf3cb56f5d5 --- /dev/null +++ b/clang/test/Sema/constexpr-member-access.c @@ -0,0 +1,54 @@ +// RUN: %clang_cc1 -std=c23 -verify -triple x86_64 -pedantic -Wno-conversion -Wno-constant-conversion -Wno-div-by-zero %s +// RUN: %clang_cc1 -std=c23 -verify -triple x86_64 -pedantic -Wno-conversion -Wno-constant-conversion -Wno-div-by-zero -fexperimental-new-constant-interpreter %s + +#define comptime_if(predicate, on_true, on_false) \ + _Generic((char (*)[1 + !!(predicate)]){0}, \ + char (*)[2]: (on_true), \ + char (*)[1]: (on_false)) + +enum E { E_A = 0, E_B = 1 }; +union U { + int a; + char b; +}; +struct S1 { + int a; +}; +struct S2 { + int a; + int b; + _Bool c; + char d; + enum E e; + struct S1 f; + double g; + int h; +}; + +constexpr struct S2 V1 = {0, 1, 1, 'c', E_B, {3}, 1.0, -1}; +constexpr union U V2 = {5}; +constexpr int V3 = V1.f.a; +constexpr int V4 = ((struct S2){0, 4, 0, 0, E_A, {6}, 0.0, 0}).f.a; + +void gh178349() { + int a[V1.b] = {}; + int b[V1.g] = {}; // expected-error {{size of array has non-integer type 'double'}} + int c[V1.h] = {}; // expected-error {{'c' declared as an array with a negative size}} + + const struct S2 *P1 = &V1; + _Static_assert(P1->b, ""); // expected-error {{static assertion expression is not an integral constant expression}} + _Static_assert(V1.b, ""); + + _Static_assert(comptime_if(V1.a, 1, 0) == 0, ""); + _Static_assert(comptime_if(V1.a, 0, 1) == 1, ""); + _Static_assert(comptime_if(V2.a, 1, 0) == 1, ""); + + _Static_assert(V1.c, ""); + _Static_assert(V1.d == 'c', ""); + _Static_assert(V1.e == E_B, ""); + _Static_assert(V1.f.a == 3, ""); + + _Static_assert(V2.a == 5, ""); + _Static_assert(V3 == 3, ""); + _Static_assert(V4 == 6, ""); +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
