llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Oleksandr Tarasiuk (a-tarasyuk)

<details>
<summary>Changes</summary>

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:

&gt; 6.6p7:
&gt; 
&gt; An identifier that is:
&gt; — an enumeration constant,
&gt; — a predefined constant, or
&gt; — declared with storage-class specifier constexpr and has an object type,
&gt; is a named constant, as is a postfix expression that applies the . member 
access operator to a named
&gt; constant of structure or union type, even recursively. For enumeration and 
predefined constants,
&gt; their value and type are defined in the respective clauses; for constexpr 
objects, such a named
&gt; constant is a constant expression with the type and value of the declared 
object.
&gt; 
&gt; § 6.6p13:
&gt; 
&gt; A structure or union constant is a named constant or compound literal 
constant with structure or
&gt; union type, respectively
&gt; 
&gt; § 6.6p15:
&gt; 
&gt; Starting from a structure or union constant, the member-access . operator 
may be used to form a
&gt; named constant or compound literal constant as described previously in 
this subclause

---
Full diff: https://github.com/llvm/llvm-project/pull/182770.diff


4 Files Affected:

- (modified) clang/docs/ReleaseNotes.rst (+1) 
- (modified) clang/lib/AST/ExprConstant.cpp (+20-1) 
- (modified) clang/test/C/drs/dr4xx.c (+1-1) 
- (added) clang/test/Sema/constexpr-member-access.c (+54) 


``````````diff
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, "");
+}

``````````

</details>


https://github.com/llvm/llvm-project/pull/182770
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to