PR44406: Follow behavior of array bound constant folding in more recent versions of GCC.
Old GCC used to aggressively fold VLAs to constant-bound arrays at block scope in GNU mode. That's non-conforming, and more modern versions of GCC only do this at file scope. Update Clang to do the same. Also promote the warning for this from off-by-default to on-by-default in all cases; more recent versions of GCC likewise warn on this by default. This is still slightly more permissive than GCC, as pointed out in PR44406, as we still fold VLAs to constant arrays in structs, but that seems justifiable given that we don't support VLA-in-struct (and don't intend to ever support it), but GCC does. Differential Revision: https://reviews.llvm.org/D89523
This commit is contained in:
@@ -2502,10 +2502,6 @@ Differences between all ``c*`` and ``gnu*`` modes:
|
||||
- The Apple "blocks" extension is recognized by default in ``gnu*`` modes
|
||||
on some platforms; it can be enabled in any mode with the ``-fblocks``
|
||||
option.
|
||||
- Arrays that are VLA's according to the standard, but which can be
|
||||
constant folded by the frontend are treated as fixed size arrays.
|
||||
This occurs for things like "int X[(1, 2)];", which is technically a
|
||||
VLA. ``c*`` modes are strictly compliant and treat these as VLAs.
|
||||
|
||||
Differences between ``*89`` and ``*94`` modes:
|
||||
|
||||
@@ -2594,10 +2590,12 @@ Intentionally unsupported GCC extensions
|
||||
the extension appears to be rarely used. Note that clang *does*
|
||||
support flexible array members (arrays with a zero or unspecified
|
||||
size at the end of a structure).
|
||||
- clang does not have an equivalent to gcc's "fold"; this means that
|
||||
clang doesn't accept some constructs gcc might accept in contexts
|
||||
where a constant expression is required, like "x-x" where x is a
|
||||
variable.
|
||||
- GCC accepts many expression forms that are not valid integer constant
|
||||
expressions in bit-field widths, enumerator constants, case labels,
|
||||
and in array bounds at global scope. Clang also accepts additional
|
||||
expression forms in these contexts, but constructs that GCC accepts due to
|
||||
simplifications GCC performs while parsing, such as ``x - x`` (where ``x`` is a
|
||||
variable) will likely never be accepted by Clang.
|
||||
- clang does not support ``__builtin_apply`` and friends; this extension
|
||||
is extremely obscure and difficult to implement reliably.
|
||||
|
||||
|
||||
@@ -137,8 +137,9 @@ def err_vla_decl_has_static_storage : Error<
|
||||
"variable length array declaration cannot have 'static' storage duration">;
|
||||
def err_vla_decl_has_extern_linkage : Error<
|
||||
"variable length array declaration cannot have 'extern' linkage">;
|
||||
def ext_vla_folded_to_constant : Extension<
|
||||
"variable length array folded to constant array as an extension">, InGroup<GNUFoldingConstant>;
|
||||
def ext_vla_folded_to_constant : ExtWarn<
|
||||
"variable length array folded to constant array as an extension">,
|
||||
InGroup<GNUFoldingConstant>;
|
||||
def err_vla_unsupported : Error<
|
||||
"variable length arrays are not supported for the current target">;
|
||||
def note_vla_unsupported : Note<
|
||||
@@ -5474,8 +5475,6 @@ def warn_flag_enum_constant_out_of_range : Warning<
|
||||
"enumeration value %0 is out of range of flags in enumeration type %1">,
|
||||
InGroup<FlagEnum>;
|
||||
|
||||
def warn_illegal_constant_array_size : Extension<
|
||||
"size of static array must be an integer constant expression">;
|
||||
def err_vm_decl_in_file_scope : Error<
|
||||
"variably modified type declaration not allowed at file scope">;
|
||||
def err_vm_decl_has_extern_linkage : Error<
|
||||
|
||||
@@ -5932,9 +5932,14 @@ static QualType TryToFixInvalidVariablyModifiedType(QualType T,
|
||||
const VariableArrayType* VLATy = dyn_cast<VariableArrayType>(T);
|
||||
if (!VLATy)
|
||||
return QualType();
|
||||
// FIXME: We should probably handle this case
|
||||
if (VLATy->getElementType()->isVariablyModifiedType())
|
||||
return QualType();
|
||||
|
||||
QualType ElemTy = VLATy->getElementType();
|
||||
if (ElemTy->isVariablyModifiedType()) {
|
||||
ElemTy = TryToFixInvalidVariablyModifiedType(ElemTy, Context,
|
||||
SizeIsNegative, Oversized);
|
||||
if (ElemTy.isNull())
|
||||
return QualType();
|
||||
}
|
||||
|
||||
Expr::EvalResult Result;
|
||||
if (!VLATy->getSizeExpr() ||
|
||||
@@ -5950,16 +5955,18 @@ static QualType TryToFixInvalidVariablyModifiedType(QualType T,
|
||||
}
|
||||
|
||||
// Check whether the array is too large to be addressed.
|
||||
unsigned ActiveSizeBits
|
||||
= ConstantArrayType::getNumAddressingBits(Context, VLATy->getElementType(),
|
||||
Res);
|
||||
unsigned ActiveSizeBits =
|
||||
(!ElemTy->isDependentType() && !ElemTy->isVariablyModifiedType() &&
|
||||
!ElemTy->isIncompleteType() && !ElemTy->isUndeducedType())
|
||||
? ConstantArrayType::getNumAddressingBits(Context, ElemTy, Res)
|
||||
: Res.getActiveBits();
|
||||
if (ActiveSizeBits > ConstantArrayType::getMaxSizeBits(Context)) {
|
||||
Oversized = Res;
|
||||
return QualType();
|
||||
}
|
||||
|
||||
return Context.getConstantArrayType(
|
||||
VLATy->getElementType(), Res, VLATy->getSizeExpr(), ArrayType::Normal, 0);
|
||||
return Context.getConstantArrayType(ElemTy, Res, VLATy->getSizeExpr(),
|
||||
ArrayType::Normal, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -5985,7 +5992,13 @@ FixInvalidVariablyModifiedTypeLoc(TypeLoc SrcTL, TypeLoc DstTL) {
|
||||
ArrayTypeLoc DstATL = DstTL.castAs<ArrayTypeLoc>();
|
||||
TypeLoc SrcElemTL = SrcATL.getElementLoc();
|
||||
TypeLoc DstElemTL = DstATL.getElementLoc();
|
||||
DstElemTL.initializeFullCopy(SrcElemTL);
|
||||
if (VariableArrayTypeLoc SrcElemATL =
|
||||
SrcElemTL.getAs<VariableArrayTypeLoc>()) {
|
||||
ConstantArrayTypeLoc DstElemATL = DstElemTL.castAs<ConstantArrayTypeLoc>();
|
||||
FixInvalidVariablyModifiedTypeLoc(SrcElemATL, DstElemATL);
|
||||
} else {
|
||||
DstElemTL.initializeFullCopy(SrcElemTL);
|
||||
}
|
||||
DstATL.setLBracketLoc(SrcATL.getLBracketLoc());
|
||||
DstATL.setSizeExpr(SrcATL.getSizeExpr());
|
||||
DstATL.setRBracketLoc(SrcATL.getRBracketLoc());
|
||||
@@ -6115,7 +6128,7 @@ Sema::CheckTypedefForVariablyModifiedType(Scope *S, TypedefNameDecl *NewTD) {
|
||||
SizeIsNegative,
|
||||
Oversized);
|
||||
if (FixedTInfo) {
|
||||
Diag(NewTD->getLocation(), diag::warn_illegal_constant_array_size);
|
||||
Diag(NewTD->getLocation(), diag::ext_vla_folded_to_constant);
|
||||
NewTD->setTypeSourceInfo(FixedTInfo);
|
||||
} else {
|
||||
if (SizeIsNegative)
|
||||
@@ -7984,7 +7997,7 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) {
|
||||
return;
|
||||
}
|
||||
|
||||
Diag(NewVD->getLocation(), diag::warn_illegal_constant_array_size);
|
||||
Diag(NewVD->getLocation(), diag::ext_vla_folded_to_constant);
|
||||
NewVD->setType(FixedT);
|
||||
NewVD->setTypeSourceInfo(FixedTInfo);
|
||||
}
|
||||
@@ -16675,7 +16688,7 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
|
||||
SizeIsNegative,
|
||||
Oversized);
|
||||
if (FixedTInfo) {
|
||||
Diag(Loc, diag::warn_illegal_constant_array_size);
|
||||
Diag(Loc, diag::ext_vla_folded_to_constant);
|
||||
TInfo = FixedTInfo;
|
||||
T = FixedTInfo->getType();
|
||||
} else {
|
||||
|
||||
@@ -2273,13 +2273,9 @@ static ExprResult checkArraySize(Sema &S, Expr *&ArraySize,
|
||||
}
|
||||
} Diagnoser(VLADiag, VLAIsError);
|
||||
|
||||
// FIXME: GCC does *not* allow folding here in general; see PR44406.
|
||||
// For GCC compatibility, we should remove this folding and leave it to
|
||||
// TryFixVariablyModifiedType to convert VLAs to constant array types.
|
||||
ExprResult R = S.VerifyIntegerConstantExpression(
|
||||
ArraySize, &SizeVal, Diagnoser,
|
||||
(S.LangOpts.GNUMode || S.LangOpts.OpenCL) ? Sema::AllowFold
|
||||
: Sema::NoFold);
|
||||
S.LangOpts.OpenCL ? Sema::AllowFold : Sema::NoFold);
|
||||
if (Diagnoser.IsVLA)
|
||||
return ExprResult();
|
||||
return R;
|
||||
|
||||
@@ -139,6 +139,7 @@ constexpr int f(ArrBad) { return 0; } // expected-error {{1st parameter type 'Ar
|
||||
constexpr int arb(int n) {
|
||||
int a[n]; // expected-error {{variable of non-literal type 'int [n]' cannot be defined in a constexpr function}}
|
||||
}
|
||||
// expected-warning@+1 {{variable length array folded to constant array as an extension}}
|
||||
constexpr long Overflow[ // expected-error {{constexpr variable cannot have non-literal type 'long const[(1 << 30) << 2]'}}
|
||||
(1 << 30) << 2]{}; // expected-warning {{requires 34 bits to represent}}
|
||||
|
||||
|
||||
@@ -898,8 +898,8 @@ namespace dr367 { // dr367: yes
|
||||
int c[true ? *new int : 4]; // expected-error 2{{variable length array}} expected-note {{read of uninitialized}}
|
||||
int d[true ? 4 : *new int];
|
||||
#if __cplusplus < 201103L
|
||||
// expected-error@-4 {{variable length array}} expected-error@-4 {{constant expression}}
|
||||
// expected-error@-3 {{variable length array}} expected-error@-3 {{constant expression}}
|
||||
// expected-error@-4 2{{variable length array}}
|
||||
// expected-error@-3 2{{variable length array}}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -210,3 +210,15 @@ void test9(int n, int a[static n]) { }
|
||||
void test10(int a[static 0]) {}
|
||||
// NULL-INVALID: define void @test10(i32* nonnull align 4 %a)
|
||||
// NULL-VALID: define void @test10(i32* align 4 %a)
|
||||
|
||||
const int constant = 32;
|
||||
// CHECK: define {{.*}}pr44406(
|
||||
int pr44406() {
|
||||
int n = 0;
|
||||
// Do not fold this VLA to an array of constant bound; that would miscompile
|
||||
// this testcase.
|
||||
char c[1][(constant - constant) + 3];
|
||||
// CHECK: store i32 1,
|
||||
sizeof(c[n = 1]);
|
||||
return n;
|
||||
}
|
||||
|
||||
@@ -91,4 +91,4 @@ CHECK-NEXT: warn_weak_import
|
||||
|
||||
The list of warnings in -Wpedantic should NEVER grow.
|
||||
|
||||
CHECK: Number in -Wpedantic (not covered by other -W flags): 27
|
||||
CHECK: Number in -Wpedantic (not covered by other -W flags): 26
|
||||
|
||||
@@ -16,7 +16,7 @@ const int b = a;
|
||||
#else
|
||||
|
||||
const int a = 5;
|
||||
typedef int T[b]; // expected-error {{variable length array}} expected-error {{must be an integer constant expression}} expected-note {{initializer of 'b'}}
|
||||
typedef int T[b]; // expected-error 2{{variable length array}} expected-note {{initializer of 'b'}}
|
||||
// expected-note@14 {{here}}
|
||||
typedef int T[5];
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ void init_arry();
|
||||
|
||||
const int inner_loop = 1000;
|
||||
const int outer_loop = 20;
|
||||
const int arry_size = 25;
|
||||
enum { arry_size = 25 };
|
||||
|
||||
int arry[arry_size] = {0};
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ void init_arry();
|
||||
|
||||
const int inner_loop = 1000;
|
||||
const int outer_loop = 20;
|
||||
const int arry_size = 25;
|
||||
enum { arry_size = 25 };
|
||||
|
||||
int arry[arry_size] = {0};
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ void init_arry();
|
||||
|
||||
const int inner_loop = 1000;
|
||||
const int outer_loop = 20;
|
||||
const int arry_size = 25;
|
||||
enum { arry_size = 25 };
|
||||
|
||||
int arry[arry_size] = {0};
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ void init_arry();
|
||||
|
||||
const int inner_loop = 1000;
|
||||
const int outer_loop = 20;
|
||||
const int arry_size = 25;
|
||||
enum { arry_size = 25 };
|
||||
|
||||
int arry[arry_size] = {0};
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ int foo(int *a, int i) {
|
||||
__builtin_assume(ispure(i) > 2);
|
||||
__builtin_assume(ispure(++i) > 2); //expected-warning {{the argument to '__builtin_assume' has side effects that will be discarded}}
|
||||
|
||||
int test = sizeof(struct{char qq[(__builtin_assume(i != 5), 7)];});
|
||||
int test = sizeof(struct{char qq[(__builtin_assume(i != 5), 7)];}); // expected-warning {{variable length array}}
|
||||
#endif
|
||||
return a[i];
|
||||
}
|
||||
|
||||
@@ -141,7 +141,7 @@ typedef __typeof(sizeof(int)) size_t;
|
||||
size_t strlen(const char *);
|
||||
|
||||
void test17() {
|
||||
#define ASSERT(...) { int arr[(__VA_ARGS__) ? 1 : -1]; }
|
||||
#define ASSERT(...) { enum { folded = (__VA_ARGS__) }; int arr[folded ? 1 : -1]; }
|
||||
#define T(...) ASSERT(__builtin_constant_p(__VA_ARGS__))
|
||||
#define F(...) ASSERT(!__builtin_constant_p(__VA_ARGS__))
|
||||
|
||||
@@ -179,12 +179,12 @@ void test17() {
|
||||
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 {{folded}}
|
||||
ASSERT(!OPT(&test17_c[0])); // expected-warning {{folded}}
|
||||
ASSERT(!OPT((char*)test17_c)); // expected-warning {{folded}}
|
||||
ASSERT(!OPT(test17_d)); // expected-warning {{folded}}
|
||||
ASSERT(!OPT(&test17_d[0])); // expected-warning {{folded}}
|
||||
ASSERT(!OPT((char*)test17_d)); // expected-warning {{folded}}
|
||||
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_d)); // expected-warning {{folding}}
|
||||
ASSERT(!OPT(&test17_d[0])); // expected-warning {{folding}}
|
||||
ASSERT(!OPT((char*)test17_d)); // expected-warning {{folding}}
|
||||
|
||||
#undef OPT
|
||||
#undef T
|
||||
|
||||
@@ -60,14 +60,16 @@ void test5(_Complex int *x) {
|
||||
(*x)++;
|
||||
}
|
||||
|
||||
int i1[(2+3i)*(5+7i) == 29i-11 ? 1 : -1];
|
||||
int i2[(29i-11)/(5+7i) == 2+3i ? 1 : -1];
|
||||
int i3[-(2+3i) == +(-3i-2) ? 1 : -1];
|
||||
int i4[~(2+3i) == 2-3i ? 1 : -1];
|
||||
int i5[(3i == -(-3i) ? ((void)3, 1i - 1) : 0) == 1i - 1 ? 1 : -1];
|
||||
// None of these array bounds is an ICE due to the use of literals of
|
||||
// non-integer type. But we can constant-fold all of them.
|
||||
int i1[(2+3i)*(5+7i) == 29i-11 ? 1 : -1]; // expected-warning {{fold}}
|
||||
int i2[(29i-11)/(5+7i) == 2+3i ? 1 : -1]; // expected-warning {{fold}}
|
||||
int i3[-(2+3i) == +(-3i-2) ? 1 : -1]; // expected-warning {{fold}}
|
||||
int i4[~(2+3i) == 2-3i ? 1 : -1]; // expected-warning {{fold}}
|
||||
int i5[(3i == -(-3i) ? ((void)3, 1i - 1) : 0) == 1i - 1 ? 1 : -1]; // expected-warning {{fold}}
|
||||
|
||||
int f1[(2.0+3.0i)*(5.0+7.0i) == 29.0i-11.0 ? 1 : -1];
|
||||
int f2[(29.0i-11.0)/(5.0+7.0i) == 2.0+3.0i ? 1 : -1];
|
||||
int f3[-(2.0+3.0i) == +(-3.0i-2.0) ? 1 : -1];
|
||||
int f4[~(2.0+3.0i) == 2.0-3.0i ? 1 : -1];
|
||||
int f5[(3.0i == -(-3.0i) ? ((void)3.0, __extension__ (1.0i - 1.0)) : 0) == 1.0i - 1.0 ? 1 : -1];
|
||||
int f1[(2.0+3.0i)*(5.0+7.0i) == 29.0i-11.0 ? 1 : -1]; // expected-warning {{fold}}
|
||||
int f2[(29.0i-11.0)/(5.0+7.0i) == 2.0+3.0i ? 1 : -1]; // expected-warning {{fold}}
|
||||
int f3[-(2.0+3.0i) == +(-3.0i-2.0) ? 1 : -1]; // expected-warning {{fold}}
|
||||
int f4[~(2.0+3.0i) == 2.0-3.0i ? 1 : -1]; // expected-warning {{fold}}
|
||||
int f5[(3.0i == -(-3.0i) ? ((void)3.0, __extension__ (1.0i - 1.0)) : 0) == 1.0i - 1.0 ? 1 : -1]; // expected-warning {{fold}}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-linux %s
|
||||
// expected-no-diagnostics
|
||||
|
||||
#define EVAL_EXPR(testno, expr) int test##testno = sizeof(struct{char qq[expr];});
|
||||
|
||||
// <rdar://problem/10962435>
|
||||
EVAL_EXPR(1, ((char*)-1LL) + 1 == 0 ? 1 : -1)
|
||||
EVAL_EXPR(2, ((char*)-1LL) + 1 < (char*) -1 ? 1 : -1)
|
||||
EVAL_EXPR(1, ((char*)-1LL) + 1 == 0 ? 1 : -1) // expected-warning {{folded}}
|
||||
EVAL_EXPR(2, ((char*)-1LL) + 1 < (char*) -1 ? 1 : -1) // expected-warning {{folded}}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-linux %s -Wno-tautological-pointer-compare -Wno-pointer-to-int-cast
|
||||
|
||||
#define EVAL_EXPR(testno, expr) int test##testno = sizeof(struct{char qq[expr];});
|
||||
#define EVAL_EXPR(testno, expr) enum { test##testno = (expr) }; struct check_positive##testno { int a[test##testno]; };
|
||||
int x;
|
||||
EVAL_EXPR(1, (_Bool)&x)
|
||||
EVAL_EXPR(2, (int)(1.0+(double)4))
|
||||
@@ -14,12 +14,12 @@ EVAL_EXPR(8, (_Bool)"asdf")
|
||||
EVAL_EXPR(9, !!&x)
|
||||
EVAL_EXPR(10, ((void)1, 12))
|
||||
void g0(void);
|
||||
EVAL_EXPR(11, (g0(), 12)) // expected-error {{must have a constant size}}
|
||||
EVAL_EXPR(11, (g0(), 12)) // expected-error {{not an integer constant expression}}
|
||||
EVAL_EXPR(12, 1.0&&2.0)
|
||||
EVAL_EXPR(13, x || 3.0) // expected-error {{must have a constant size}}
|
||||
EVAL_EXPR(13, x || 3.0) // expected-error {{not an integer constant expression}}
|
||||
|
||||
unsigned int l_19 = 1;
|
||||
EVAL_EXPR(14, (1 ^ l_19) && 1); // expected-error {{fields must have a constant size}}
|
||||
EVAL_EXPR(14, (1 ^ l_19) && 1); // expected-error {{not an integer constant expression}}
|
||||
|
||||
void f()
|
||||
{
|
||||
@@ -36,7 +36,7 @@ int g17[(3?:1) - 2];
|
||||
EVAL_EXPR(18, ((int)((void*)10 + 10)) == 20 ? 1 : -1);
|
||||
|
||||
struct s {
|
||||
int a[(int)-1.0f]; // expected-error {{'a' declared as an array with a negative size}}
|
||||
int a[(int)-1.0f]; // expected-error {{array size is negative}}
|
||||
};
|
||||
|
||||
EVAL_EXPR(19, ((int)&*(char*)10 == 10 ? 1 : -1));
|
||||
@@ -47,9 +47,9 @@ EVAL_EXPR(21, (__imag__ 2i) == 2 ? 1 : -1);
|
||||
|
||||
EVAL_EXPR(22, (__real__ (2i+3)) == 3 ? 1 : -1);
|
||||
|
||||
int g23[(int)(1.0 / 1.0)] = { 1 };
|
||||
int g24[(int)(1.0 / 1.0)] = { 1 , 2 }; // expected-warning {{excess elements in array initializer}}
|
||||
int g25[(int)(1.0 + 1.0)], g26 = sizeof(g25);
|
||||
int g23[(int)(1.0 / 1.0)] = { 1 }; // expected-warning {{folded to constant array}}
|
||||
int g24[(int)(1.0 / 1.0)] = { 1 , 2 }; // expected-warning {{folded to constant array}} expected-warning {{excess elements in array initializer}}
|
||||
int g25[(int)(1.0 + 1.0)], g26 = sizeof(g25); // expected-warning {{folded to constant array}}
|
||||
|
||||
EVAL_EXPR(26, (_Complex double)0 ? -1 : 1)
|
||||
EVAL_EXPR(27, (_Complex int)0 ? -1 : 1)
|
||||
@@ -116,17 +116,17 @@ EVAL_EXPR(42, __builtin_constant_p(pr11391.f = 1))
|
||||
// PR12043
|
||||
float varfloat;
|
||||
const float constfloat = 0;
|
||||
EVAL_EXPR(43, varfloat && constfloat) // expected-error {{must have a constant size}}
|
||||
EVAL_EXPR(43, varfloat && constfloat) // expected-error {{not an integer constant expression}}
|
||||
|
||||
// <rdar://problem/10962435>
|
||||
EVAL_EXPR(45, ((char*)-1) + 1 == 0 ? 1 : -1)
|
||||
EVAL_EXPR(46, ((char*)-1) + 1 < (char*) -1 ? 1 : -1)
|
||||
EVAL_EXPR(47, &x < &x + 1 ? 1 : -1)
|
||||
EVAL_EXPR(48, &x != &x - 1 ? 1 : -1)
|
||||
EVAL_EXPR(49, &x < &x - 100 ? 1 : -1) // expected-error {{must have a constant size}}
|
||||
EVAL_EXPR(49, &x < &x - 100 ? 1 : -1) // expected-error {{not an integer constant expression}}
|
||||
|
||||
extern struct Test50S Test50;
|
||||
EVAL_EXPR(50, &Test50 < (struct Test50S*)((unsigned long)&Test50 + 10)) // expected-error {{must have a constant size}}
|
||||
EVAL_EXPR(50, &Test50 < (struct Test50S*)((unsigned long)&Test50 + 10)) // expected-error {{not an integer constant expression}}
|
||||
|
||||
// <rdar://problem/11874571>
|
||||
EVAL_EXPR(51, 0 != (float)1e99)
|
||||
@@ -136,7 +136,7 @@ void PR21945() { int i = (({}), 0l); }
|
||||
|
||||
void PR24622();
|
||||
struct PR24622 {} pr24622;
|
||||
EVAL_EXPR(52, &pr24622 == (void *)&PR24622); // expected-error {{must have a constant size}}
|
||||
EVAL_EXPR(52, &pr24622 == (void *)&PR24622); // expected-error {{not an integer constant expression}}
|
||||
|
||||
// We evaluate these by providing 2s' complement semantics in constant
|
||||
// expressions, like we do for integers.
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
// RUN: %clang_cc1 -fsyntax-only -Wno-pointer-to-int-cast -verify %s
|
||||
// expected-no-diagnostics
|
||||
typedef long unsigned int __darwin_size_t;
|
||||
typedef long __darwin_ssize_t;
|
||||
typedef __darwin_size_t size_t;
|
||||
@@ -18,6 +17,7 @@ i386/_param.h:#define __DARWIN_ALIGN(p) ((__darwin_size_t)((char *)(p)
|
||||
|
||||
ssize_t sendFileDescriptor(int fd, void *data, size_t nbytes, int sendfd) {
|
||||
union {
|
||||
// expected-warning@+1 {{folded to constant array}}
|
||||
char control[(((__darwin_size_t)((char *)(sizeof(struct cmsghdr)) + (sizeof(__darwin_size_t) - 1)) &~ (sizeof(__darwin_size_t) - 1)) + ((__darwin_size_t)((char *)(sizeof(int)) + (sizeof(__darwin_size_t) - 1)) &~ (sizeof(__darwin_size_t) - 1)))];
|
||||
} control_un;
|
||||
return 0;
|
||||
|
||||
@@ -49,7 +49,7 @@ void f(struct q *, struct __attribute__((aligned(4))) q *); // expected-warning
|
||||
// function.
|
||||
enum { BB = 0 };
|
||||
void enum_in_fun_in_fun(void (*fp)(enum { AA, BB } e)) { // expected-warning {{will not be visible}}
|
||||
SA(1, AA == 5);
|
||||
SA(1, AA == 5); // expected-error {{variable-sized object may not be initialized}}
|
||||
SA(2, BB == 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -124,7 +124,9 @@ enum {
|
||||
fic = (int)(0.75 * 1000 * 1000)
|
||||
};
|
||||
static const int size = 100;
|
||||
void foo(void) { int data[size]; }
|
||||
int data[size];
|
||||
|
||||
void foo(void) { int data[size]; } // OK, always a VLA
|
||||
|
||||
#if ALL || REDECLAREDENUM
|
||||
// expected-note@+4 {{previous definition is here}}
|
||||
|
||||
@@ -12,7 +12,7 @@ char w[__builtin_constant_p(expr) ? expr : 1];
|
||||
char v[sizeof(__builtin_constant_p(0)) == sizeof(int) ? 1 : -1];
|
||||
|
||||
int implicitConversion = 1.0;
|
||||
char floatArith[(int)(1.0+2.0)]; // expected-warning {{must be an integer constant expression}}
|
||||
char floatArith[(int)(1.0+2.0)]; // expected-warning {{variable length array folded to constant array as an extension}}
|
||||
|
||||
// __builtin_constant_p as the condition of ?: allows arbitrary foldable
|
||||
// constants to be transmogrified into i-c-e's.
|
||||
@@ -57,7 +57,7 @@ char z[__builtin_constant_p(4) ? 1 : -1];
|
||||
int comma1[0?1,2:3];
|
||||
int comma2[1||(1,2)]; // expected-warning {{use of logical '||' with constant operand}} \
|
||||
// expected-note {{use '|' for a bitwise operation}}
|
||||
int comma3[(1,2)]; // expected-warning {{size of static array must be an integer constant expression}}
|
||||
int comma3[(1,2)]; // expected-warning {{variable length array folded to constant array as an extension}}
|
||||
|
||||
// Pointer + __builtin_constant_p
|
||||
char pbcp[__builtin_constant_p(4) ? (intptr_t)&expr : 0]; // expected-error {{variable length array declaration not allowed at file scope}}
|
||||
|
||||
@@ -5,15 +5,15 @@
|
||||
const unsigned long Size = (1l << 60);
|
||||
|
||||
struct Chunk1 {
|
||||
char padding[Size];
|
||||
char more_padding[1][Size];
|
||||
char padding[Size]; // expected-warning {{folded to constant}}
|
||||
char more_padding[1][Size]; // expected-warning {{folded to constant}}
|
||||
char data;
|
||||
};
|
||||
|
||||
int test1 = __builtin_offsetof(struct Chunk1, data);
|
||||
|
||||
struct Chunk2 {
|
||||
char padding[Size][Size][Size]; // expected-error 2{{array is too large}}
|
||||
char padding[Size][Size][Size]; // expected-error {{array is too large}}
|
||||
char data;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// RUN: %clang_cc1 -triple x86_64-linux -verify=norounding %s
|
||||
// RUN: %clang_cc1 -triple x86_64-linux -std=c17 -verify=rounding-std %s -frounding-math
|
||||
// RUN: %clang_cc1 -triple x86_64-linux -std=gnu17 -verify=rounding-gnu %s -frounding-math
|
||||
// RUN: %clang_cc1 -triple x86_64-linux -std=c17 -verify=expected,norounding %s
|
||||
// RUN: %clang_cc1 -triple x86_64-linux -std=gnu17 -verify=expected,norounding %s
|
||||
// RUN: %clang_cc1 -triple x86_64-linux -std=c17 -verify=expected,rounding %s -frounding-math
|
||||
// RUN: %clang_cc1 -triple x86_64-linux -std=gnu17 -verify=expected,rounding %s -frounding-math
|
||||
|
||||
#define fold(x) (__builtin_constant_p(x) ? (x) : (x))
|
||||
|
||||
@@ -24,8 +25,11 @@ void bitfield(struct Bitfield *b) {
|
||||
}
|
||||
|
||||
void vlas() {
|
||||
// Under -frounding-math, this is a VLA.
|
||||
// FIXME: Due to PR44406, in GNU mode we constant-fold the initializer resulting in a non-VLA.
|
||||
typedef int vla[(int)(-3 * (1.0 / 3.0))]; // norounding-error {{negative size}} rounding-gnu-error {{negative size}}
|
||||
struct X { vla v; }; // rounding-std-error {{fields must have a constant size}}
|
||||
// This is always a VLA due to its syntactic form.
|
||||
typedef int vla1[(int)(-3 * (1.0 / 3.0))];
|
||||
struct X1 { vla1 v; }; // expected-error {{fields must have a constant size}}
|
||||
|
||||
// This is always folded to a constant.
|
||||
typedef int vla2[fold((int)(-3 * (1.0 / 3.0)))]; // expected-error {{negative size}}
|
||||
struct X2 { vla2 v; };
|
||||
}
|
||||
|
||||
@@ -5,8 +5,8 @@ struct bar {
|
||||
};
|
||||
|
||||
struct foo {
|
||||
char name[(int)&((struct bar *)0)->n];
|
||||
char name2[(int)&((struct bar *)0)->n - 1]; //expected-error{{'name2' declared as an array with a negative size}}
|
||||
char name[(int)&((struct bar *)0)->n]; // expected-warning {{folded to constant}}
|
||||
char name2[(int)&((struct bar *)0)->n - 1]; // expected-error {{array size is negative}}
|
||||
};
|
||||
|
||||
// PR3430
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// RUN: %clang_cc1 %s -verify -fsyntax-only -pedantic -Wno-typedef-redefinition -std=c99
|
||||
|
||||
// Make sure we accept a single typedef
|
||||
typedef int (*a)[!.0]; // expected-warning{{size of static array must be an integer constant expression}}
|
||||
typedef int (*a)[!.0]; // expected-warning{{folded to constant array}}
|
||||
|
||||
// And make sure we accept identical redefinitions in system headers
|
||||
// (The test uses -Wno-typedef-redefinition to simulate this.)
|
||||
typedef int (*a)[!.0]; // expected-warning{{size of static array must be an integer constant expression}}
|
||||
typedef int (*a)[!.0]; // expected-warning{{folded to constant array}}
|
||||
|
||||
@@ -53,7 +53,7 @@ int pr2044b;
|
||||
int (*pr2044c(void))[pr2044b]; // expected-error {{variably modified type}}
|
||||
|
||||
const int f5_ci = 1;
|
||||
void f5() { char a[][f5_ci] = {""}; } // expected-warning {{variable length array folded to constant array as an extension}}
|
||||
void f5() { char a[][f5_ci] = {""}; } // expected-error {{variable-sized object may not be initialized}}
|
||||
|
||||
// PR5185
|
||||
void pr5185(int a[*]);
|
||||
@@ -89,3 +89,14 @@ void VLAPtrAssign(int size) {
|
||||
// Not illegal in C, program _might_ be well formed if size == 3.
|
||||
int (*p4)[2][size][3][4][5] = array;
|
||||
}
|
||||
|
||||
void pr44406() {
|
||||
goto L; // expected-error {{cannot jump}}
|
||||
int z[(int)(1.0 * 2)]; // expected-note {{bypasses initialization of variable length array}}
|
||||
L:;
|
||||
}
|
||||
|
||||
const int pr44406_a = 32;
|
||||
typedef struct {
|
||||
char c[pr44406_a]; // expected-warning {{folded to constant array as an extension}}
|
||||
} pr44406_s;
|
||||
|
||||
@@ -131,6 +131,9 @@ namespace ValidButUnsupported {
|
||||
typedef struct { // expected-error {{unsupported}}
|
||||
enum X {};
|
||||
int arr[&f<X> ? 1 : 2];
|
||||
#if __cplusplus < 201103L
|
||||
// expected-warning@-2 {{folded to constant}}
|
||||
#endif
|
||||
} C; // expected-note {{by this typedef}}
|
||||
}
|
||||
|
||||
|
||||
@@ -110,7 +110,7 @@ extern const int recurse1;
|
||||
const int recurse2 = recurse1; // expected-note {{here}}
|
||||
const int recurse1 = 1;
|
||||
int array1[recurse1]; // ok
|
||||
int array2[recurse2]; // expected-warning {{variable length array}} expected-warning {{integer constant expression}} expected-note {{initializer of 'recurse2' is not a constant expression}}
|
||||
int array2[recurse2]; // expected-warning 2{{variable length array}} expected-note {{initializer of 'recurse2' is not a constant expression}}
|
||||
|
||||
namespace FloatConvert {
|
||||
typedef int a[(int)42.3];
|
||||
|
||||
@@ -120,7 +120,7 @@ namespace Builtins {
|
||||
extern "C" int strncmp(const char *, const char *, decltype(sizeof(0))) noexcept;
|
||||
|
||||
// Check we recognized both as builtins.
|
||||
typedef int arr[strcmp("bar", "foo") + 4 * strncmp("foo", "bar", 4)];
|
||||
typedef int arr[strcmp("bar", "foo") + 4 * strncmp("foo", "bar", 4)]; // expected-warning {{variable length array}}
|
||||
typedef int arr[3];
|
||||
}
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ struct PR8836 { char _; long long a; };
|
||||
#endif
|
||||
|
||||
int PR8836test[(__typeof(sizeof(int)))&reinterpret_cast<const volatile char&>((((PR8836*)0)->a))];
|
||||
// expected-warning@-1 {{folded to constant array as an extension}}
|
||||
// expected-warning@-1 0-1{{C99 feature}} expected-warning@-1 {{folded to constant array as an extension}}
|
||||
// expected-note@-2 {{cast that performs the conversions of a reinterpret_cast is not allowed in a constant expression}}
|
||||
|
||||
const int nonconst = 1.0;
|
||||
@@ -89,7 +89,7 @@ const int nonconst = 1.0;
|
||||
#endif
|
||||
int arr[nonconst];
|
||||
#if __cplusplus <= 199711L
|
||||
// expected-warning@-2 {{folded to constant array as an extension}}
|
||||
// expected-warning@-2 0-1{{C99 feature}} expected-warning@-2 {{folded to constant array as an extension}}
|
||||
// expected-note@-3 {{initializer of 'nonconst' is not a constant expression}}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ typedef struct _NSRange { } NSRange;
|
||||
|
||||
// GCC allows pointer expressions in integer constant expressions.
|
||||
struct {
|
||||
char control[((int)(char *)2)];
|
||||
char control[((int)(char *)2)]; // expected-warning {{extension}}
|
||||
} xx;
|
||||
|
||||
@implementation PBXDocBookmark // expected-warning {{method definition for 'autorelease' not found}}\
|
||||
|
||||
Reference in New Issue
Block a user