diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -179,6 +179,9 @@ _Generic(i, int : 0, const int : 1); // Warns about unreachable code, the // result is 0, not 1. _Generic(typeof(i), int : 0, const int : 1); // Result is 1, not 0. +- ``structs``, ``unions``, and ``arrays`` that are const may now be used as + constant expressions. This change is more consistent with the behavior of + GCC. C2x Feature Support ^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -15218,14 +15218,6 @@ return true; } - // FIXME: Evaluating values of large array and record types can cause - // performance problems. Only do so in C++11 for now. - if (Exp->isPRValue() && - (Exp->getType()->isArrayType() || Exp->getType()->isRecordType()) && - !Ctx.getLangOpts().CPlusPlus11) { - IsConst = false; - return true; - } return false; } @@ -15467,12 +15459,6 @@ return Name; }); - // FIXME: Evaluating initializers for large array and record types can cause - // performance problems. Only do so in C++11 for now. - if (isPRValue() && (getType()->isArrayType() || getType()->isRecordType()) && - !Ctx.getLangOpts().CPlusPlus11) - return false; - Expr::EvalStatus EStatus; EStatus.Diag = &Notes; diff --git a/clang/test/CodeGen/builtin-constant-p.c b/clang/test/CodeGen/builtin-constant-p.c --- a/clang/test/CodeGen/builtin-constant-p.c +++ b/clang/test/CodeGen/builtin-constant-p.c @@ -76,7 +76,7 @@ int test7(void) { // CHECK-LABEL: test7 - // CHECK: call i1 @llvm.is.constant.i32 + // CHECK: ret i32 1 return __builtin_constant_p(c_arr[2]); } 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 @@ -190,3 +190,28 @@ struct { const float *floats; } compoundliteral = { (float[1]) { 0.1, }, }; + +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/builtins.c b/clang/test/Sema/builtins.c --- a/clang/test/Sema/builtins.c +++ b/clang/test/Sema/builtins.c @@ -131,7 +131,7 @@ const int test17_n = 0; const char test17_c[] = {1, 2, 3, 0}; -const char test17_d[] = {1, 2, 3, 4}; +const char test17_d[] = {1, 2, 3, 4}; // Like test17_c but not NUL-terminated. typedef int __attribute__((vector_size(16))) IntVector; struct Aggregate { int n; char c; }; enum Enum { EnumValue1, EnumValue2 }; @@ -178,9 +178,10 @@ ASSERT(!OPT("abcd")); // In these cases, the strlen is non-constant, but the __builtin_constant_p // is 0: the array size is not an ICE but is foldable. - ASSERT(!OPT(test17_c)); // expected-warning {{folding}} - ASSERT(!OPT(&test17_c[0])); // expected-warning {{folding}} - ASSERT(!OPT((char*)test17_c)); // expected-warning {{folding}} + ASSERT(!OPT(test17_c)); + ASSERT(!OPT(&test17_c[0])); + ASSERT(!OPT((char*)test17_c)); + // NOTE: test17_d is not NUL-termintated, so calling strlen on it is UB. ASSERT(!OPT(test17_d)); // expected-warning {{folding}} ASSERT(!OPT(&test17_d[0])); // expected-warning {{folding}} ASSERT(!OPT((char*)test17_d)); // expected-warning {{folding}} 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 @@ -164,3 +164,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]; // expected-error {{initializer element is not a compile-time constant}} +int PR4517_x3 = PR4517_a[0]; // expected-error {{initializer element is not a compile-time constant}} +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