nickdesaulniers updated this revision to Diff 250319.
nickdesaulniers added a comment.

- add support for compile time arrays


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D76096/new/

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/array-init.c
  clang/test/Sema/const-eval.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,36 @@
 
 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
+};
+extern const struct PR4517_foo my_foo2;
+struct PR4517_bar my_bar5 = {
+  .foo = my_foo2, // expected-error {{initializer element is not a compile-time constant}}
+};
+int PR4517_a[2] = {0, 1};
+const int PR4517_ca[2] = {0, 1};
+int PR4517_idx = 0;
+const int PR4517_idxc = 1;
+int PR4517_x1 = PR4517_a[PR4517_idx]; // expected-error {{initializer element is not a compile-time constant}}
+int PR4517_x2 = PR4517_a[PR4517_idxc]; // should error
+int PR4517_x3 = PR4517_a[0]; // should error
+int PR4517_y1 = PR4517_ca[PR4517_idx]; // expected-error {{initializer element is not a compile-time constant}}
+int PR4517_y2 = PR4517_ca[PR4517_idxc]; // no-warning
+int PR4517_y3 = PR4517_ca[0]; // no-warning
Index: clang/test/Sema/const-eval.c
===================================================================
--- clang/test/Sema/const-eval.c
+++ clang/test/Sema/const-eval.c
@@ -150,5 +150,5 @@
   int arr[];
 };
 int PR35214_x;
-int PR35214_y = ((struct PR35214_X *)&PR35214_x)->arr[1]; // expected-error {{not a compile-time constant}}
+int PR35214_y = ((struct PR35214_X *)&PR35214_x)->arr[1];
 int *PR35214_z = &((struct PR35214_X *)&PR35214_x)->arr[1]; // ok, &PR35214_x + 2
Index: clang/test/Sema/array-init.c
===================================================================
--- clang/test/Sema/array-init.c
+++ clang/test/Sema/array-init.c
@@ -268,7 +268,7 @@
   };
 }
 
-char badchararray[1] = { badchararray[0], "asdf" }; // expected-warning {{excess elements in array initializer}} expected-error {{initializer element is not a compile-time constant}}
+char badchararray[1] = { badchararray[0], "asdf" }; // expected-warning {{excess elements in array initializer}}
 
 // Test the GNU extension for initializing an array from an array
 // compound literal. PR9261.
Index: clang/test/CodeGen/const-init.c
===================================================================
--- clang/test/CodeGen/const-init.c
+++ clang/test/CodeGen/const-init.c
@@ -181,3 +181,28 @@
 #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
+const int PR4517_arrc[2] = {41, 42};
+int PR4517_x = PR4517_arrc[1];
+const int PR4517_idx = 1;
+int PR4517_x2 = PR4517_arrc[PR4517_idx];
+// CHECK: @PR4517_arrc = constant [2 x i32] [i32 41, i32 42], align 4
+// CHECK: @PR4517_x = global i32 42, align 4
+// CHECK: @PR4517_idx = constant i32 1, align 4
+// CHECK: @PR4517_x2 = global i32 42, align 4
Index: clang/lib/CodeGen/CGExprConstant.cpp
===================================================================
--- clang/lib/CodeGen/CGExprConstant.cpp
+++ clang/lib/CodeGen/CGExprConstant.cpp
@@ -1007,6 +1007,40 @@
     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 *VisitIntegerLiteral(IntegerLiteral* IL, QualType T) {
+    llvm::APInt I = IL->getValue();
+    auto IT = llvm::IntegerType::get(CGM.getLLVMContext(), I.getBitWidth());
+    return llvm::ConstantInt::get(IT, I.getSExtValue(), I.isSignBitSet());
+  }
+
+  llvm::Constant *VisitArraySubscriptExpr(ArraySubscriptExpr *ASE, QualType T) {
+    // index
+    llvm::Optional<llvm::APInt> id;
+    if (auto *ICE = dyn_cast<ImplicitCastExpr>(ASE->getIdx())) {
+      if (auto *DRE = dyn_cast<DeclRefExpr>(ICE->getSubExpr()))
+        if (auto *V = dyn_cast<VarDecl>(DRE->getDecl()))
+          if (auto *I = dyn_cast<IntegerLiteral>(V->getInit()))
+            id = I->getValue();
+    } else if (auto *I = dyn_cast<IntegerLiteral>(ASE->getIdx())) {
+      id = I->getValue();
+    }
+    // base
+    if (id.hasValue())
+      if (auto *ICE = dyn_cast<ImplicitCastExpr>(ASE->getBase()))
+        if (auto *DRE = dyn_cast<DeclRefExpr>(ICE->getSubExpr()))
+          if (auto *V = dyn_cast<VarDecl>(DRE->getDecl()))
+            if (V->hasInit())
+              return Visit(cast<InitListExpr>(V->getInit())->getInit(id->getSExtValue()), T);
+    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,22 @@
 
   switch (getStmtClass()) {
   default: break;
+  case ArraySubscriptExprClass:
+    if (!Ctx.getLangOpts().CPlusPlus) {
+      const auto *ASEC = cast<ArraySubscriptExpr>(this);
+      if (ASEC->getIdx()->isConstantInitializer(Ctx, false, Culprit) &&
+          ASEC->getBase()->isConstantInitializer(Ctx, false, Culprit))
+        return true;
+    }
+    break;
+  case DeclRefExprClass:
+    if (!Ctx.getLangOpts().CPlusPlus)
+      if (auto *VD = dyn_cast<VarDecl>(cast<DeclRefExpr>(this)->getDecl())) {
+        const QualType &QT = VD->getType();
+        if (VD->hasInit() && QT->isStructureType() && QT.isConstQualified())
+          return true;
+      }
+    break;
   case StringLiteralClass:
   case ObjCEncodeExprClass:
     return true;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to