diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -3158,6 +3158,22 @@ switch (getStmtClass()) { default: break; + case ArraySubscriptExprClass: + if (!Ctx.getLangOpts().CPlusPlus) { + const auto *ASEC = cast(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(cast(this)->getDecl())) { + const QualType &QT = VD->getType(); + if (VD->hasInit() && QT->isStructureType() && QT.isConstQualified()) + return true; + } + break; case StringLiteralClass: case ObjCEncodeExprClass: return true; diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp --- a/clang/lib/CodeGen/CGExprConstant.cpp +++ b/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(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 id; + if (auto *ICE = dyn_cast(ASE->getIdx())) { + if (auto *DRE = dyn_cast(ICE->getSubExpr())) + if (auto *V = dyn_cast(DRE->getDecl())) + if (auto *I = dyn_cast(V->getInit())) + id = I->getValue(); + } else if (auto *I = dyn_cast(ASE->getIdx())) { + id = I->getValue(); + } + // base + if (id.hasValue()) + if (auto *ICE = dyn_cast(ASE->getBase())) + if (auto *DRE = dyn_cast(ICE->getSubExpr())) + if (auto *V = dyn_cast(DRE->getDecl())) + if (V->hasInit()) + return Visit(cast(V->getInit())->getInit(id->getSExtValue()), T); + return nullptr; + } + llvm::Constant * VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *PE, QualType T) { diff --git a/clang/test/CodeGen/const-init.c b/clang/test/CodeGen/const-init.c --- a/clang/test/CodeGen/const-init.c +++ b/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 diff --git a/clang/test/Sema/array-init.c b/clang/test/Sema/array-init.c --- a/clang/test/Sema/array-init.c +++ b/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. diff --git a/clang/test/Sema/const-eval.c b/clang/test/Sema/const-eval.c --- a/clang/test/Sema/const-eval.c +++ b/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 diff --git a/clang/test/Sema/init.c b/clang/test/Sema/init.c --- a/clang/test/Sema/init.c +++ b/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