[PATCH] D76096: [clang] allow const structs to be constant expressions in initializer lists

Nick Desaulniers via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Thu Mar 12 14:07:09 PDT 2020


nickdesaulniers created this revision.
nickdesaulniers added reviewers: eli.friedman, aaron.ballman, rsmith.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.
nickdesaulniers updated this revision to Diff 250046.
nickdesaulniers added a comment.
nickdesaulniers marked an inline comment as done.
nickdesaulniers added subscribers: void, jyknight.
nickdesaulniers marked an inline comment as not done.

- add 2 missing CHECKs



================
Comment at: clang/lib/AST/Expr.cpp:3164
+      const QualType &QT = cast<DeclRefExpr>(this)->getDecl()->getType();
+      if (QT->isStructureType() && QT.isConstQualified())
+        return true;
----------------
Interesting, playing with this more in godbolt, it looks like the struct doesn't even have to be const qualified.


================
Comment at: clang/lib/AST/Expr.cpp:3164
+      const QualType &QT = cast<DeclRefExpr>(this)->getDecl()->getType();
+      if (QT->isStructureType() && QT.isConstQualified())
+        return true;
----------------
nickdesaulniers wrote:
> Interesting, playing with this more in godbolt, it looks like the struct doesn't even have to be const qualified.
Or, rather, behaves differently between C and C++ mode;

C -> const required
C++ -> const not required


This seems to be an undocumented GNU C extension.

For code like:
struct foo { ... };
struct bar { struct foo foo; };
struct foo my_foo = { ... };
struct bar my_bar = { .foo = my_foo };

during CodeGen of LLVM IR, copy the initializer of `my_foo` into the
initializer of `my_bar` recursively.

Eli Friedman points out the relevant part of the C standard seems to
have some flexibility in what is considered a constant expression:

6.6 paragraph 10:
An implementation may accept other forms of constant expressions.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D76096

Files:
  clang/lib/AST/Expr.cpp
  clang/lib/CodeGen/CGExprConstant.cpp
  clang/test/CodeGen/const-init.c
  clang/test/Sema/init.c


Index: clang/test/Sema/init.c
===================================================================
--- clang/test/Sema/init.c
+++ clang/test/Sema/init.c
@@ -160,3 +160,22 @@
 
 typedef struct { uintptr_t x : 2; } StructWithBitfield;
 StructWithBitfield bitfieldvar = { (uintptr_t)&bitfieldvar }; // expected-error {{initializer element is not a compile-time constant}}
+
+// PR45157
+struct PR4517_foo {};
+struct PR4517_bar {
+  struct PR4517_foo foo;
+};
+const struct PR4517_foo my_foo = {};
+struct PR4517_bar my_bar = {
+    .foo = my_foo, // no-warning
+};
+struct PR4517_bar my_bar2 = (struct PR4517_bar){
+    .foo = my_foo, // no-warning
+};
+struct PR4517_bar my_bar3 = {
+    my_foo, // no-warning
+};
+struct PR4517_bar my_bar4 = (struct PR4517_bar){
+    my_foo // no-warning
+};
Index: clang/test/CodeGen/const-init.c
===================================================================
--- clang/test/CodeGen/const-init.c
+++ clang/test/CodeGen/const-init.c
@@ -181,3 +181,20 @@
 #pragma pack()
   // CHECK: @g31.a = internal global %struct.anon.2 { i16 23122, i32 -12312731, i16 -312 }, align 4
 }
+
+struct PR4517_foo {
+  int x;
+};
+struct PR4517_bar {
+  struct PR4517_foo foo;
+};
+const struct PR4517_foo my_foo = {.x = 42};
+struct PR4517_bar my_bar = {.foo = my_foo};
+struct PR4517_bar my_bar2 = (struct PR4517_bar){.foo = my_foo};
+struct PR4517_bar my_bar3 = {my_foo};
+struct PR4517_bar my_bar4 = (struct PR4517_bar){my_foo};
+// CHECK: @my_foo = constant %struct.PR4517_foo { i32 42 }, align 4
+// CHECK: @my_bar = global %struct.PR4517_bar { %struct.PR4517_foo { i32 42 } }, align 4
+// CHECK: @my_bar2 = global %struct.PR4517_bar { %struct.PR4517_foo { i32 42 } }, align 4
+// CHECK: @my_bar3 = global %struct.PR4517_bar { %struct.PR4517_foo { i32 42 } }, align 4
+// CHECK: @my_bar4 = global %struct.PR4517_bar { %struct.PR4517_foo { i32 42 } }, align 4
Index: clang/lib/CodeGen/CGExprConstant.cpp
===================================================================
--- clang/lib/CodeGen/CGExprConstant.cpp
+++ clang/lib/CodeGen/CGExprConstant.cpp
@@ -1007,6 +1007,13 @@
     return Visit(PE->getSubExpr(), T);
   }
 
+  llvm::Constant *VisitDeclRefExpr(DeclRefExpr *DRE, QualType T) {
+    if (VarDecl *V = dyn_cast<VarDecl>(DRE->getDecl()))
+      if (V->hasInit())
+        return Visit(V->getInit(), V->getType());
+    return nullptr;
+  }
+
   llvm::Constant *
   VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *PE,
                                     QualType T) {
Index: clang/lib/AST/Expr.cpp
===================================================================
--- clang/lib/AST/Expr.cpp
+++ clang/lib/AST/Expr.cpp
@@ -3158,6 +3158,13 @@
 
   switch (getStmtClass()) {
   default: break;
+  case DeclRefExprClass:
+    if (!Ctx.getLangOpts().CPlusPlus && Ctx.getLangOpts().GNUMode) {
+      const QualType &QT = cast<DeclRefExpr>(this)->getDecl()->getType();
+      if (QT->isStructureType() && QT.isConstQualified())
+        return true;
+    }
+    break;
   case StringLiteralClass:
   case ObjCEncodeExprClass:
     return true;


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D76096.250046.patch
Type: text/x-patch
Size: 3090 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20200312/f2569e9f/attachment-0001.bin>


More information about the cfe-commits mailing list