Skip to content

Commit 7f93ae8

Browse files
committed
[clang] Implement -fstrict-flex-arrays=3
The -fstrict-flex-arrays=3 is the most restrictive type of flex arrays. No number, including 0, is allowed in the FAM. In the cases where a "0" is used, the resulting size is the same as if a zero-sized object were substituted. This is needed for proper _FORTIFY_SOURCE coverage in the Linux kernel, among other reasons. So while the only reason for specifying a zero-length array at the end of a structure is for specify a FAM, treating it as such will cause _FORTIFY_SOURCE not to work correctly; __builtin_object_size will report -1 instead of 0 for a destination buffer size to keep any kernel internals from using the deprecated members as fake FAMs. For example: struct broken { int foo; int fake_fam[0]; struct something oops; }; There have been bugs where the above struct was created because "oops" was added after "fake_fam" by someone not realizing. Under __FORTIFY_SOURCE, doing: memcpy(p->fake_fam, src, len); raises no warnings when __builtin_object_size(p->fake_fam, 1) returns -1 and may stomp on "oops." Omitting a warning when using the (invalid) zero-length array is how GCC treats -fstrict-flex-arrays=3. A warning in that situation is likely an irritant, because requesting this option level is explicitly requesting this behavior. Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101836 Differential Revision: https://reviews.llvm.org/D134902
1 parent 015bc34 commit 7f93ae8

File tree

10 files changed

+139
-32
lines changed

10 files changed

+139
-32
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,9 +391,27 @@ New Compiler Flags
391391
`::operator new(size_­t, std::aligned_val_t, nothrow_­t)` if there is
392392
`get_­return_­object_­on_­allocation_­failure`. We feel this is more consistent
393393
with the intention.
394+
394395
- Added ``--no-default-config`` to disable automatically loading configuration
395396
files using default paths.
396397

398+
- Added the new level, ``3``, to the ``-fstrict-flex-arrays=`` flag. The new
399+
level is the strict, standards-conforming mode for flexible array members. It
400+
recognizes only incomplete arrays as flexible array members (which is how the
401+
feature is defined by the C standard).
402+
403+
.. code-block:: c
404+
405+
struct foo {
406+
int a;
407+
int b[]; // Flexible array member.
408+
};
409+
410+
struct bar {
411+
int a;
412+
int b[0]; // NOT a flexible array member.
413+
};
414+
397415
Deprecated Compiler Flags
398416
-------------------------
399417
- ``-enable-trivial-auto-var-init-zero-knowing-it-will-be-removed-from-clang``

clang/include/clang/Basic/LangOptions.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,7 @@ class LangOptions : public LangOptionsBase {
377377
/// Any trailing array member of undefined or 0 size is a FAM.
378378
ZeroOrIncomplete = 2,
379379
/// Any trailing array member of undefined size is a FAM.
380-
Incomplete = 3,
380+
IncompleteOnly = 3,
381381
};
382382

383383
public:

clang/include/clang/Driver/Options.td

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1151,11 +1151,11 @@ def fapple_kext : Flag<["-"], "fapple-kext">, Group<f_Group>, Flags<[CC1Option]>
11511151
HelpText<"Use Apple's kernel extensions ABI">,
11521152
MarshallingInfoFlag<LangOpts<"AppleKext">>;
11531153
def fstrict_flex_arrays_EQ : Joined<["-"], "fstrict-flex-arrays=">, Group<f_Group>,
1154-
MetaVarName<"<n>">, Values<"0,1,2">,
1154+
MetaVarName<"<n>">, Values<"0,1,2,3">,
11551155
LangOpts<"StrictFlexArraysLevel">,
11561156
Flags<[CC1Option]>,
11571157
NormalizedValuesScope<"LangOptions::StrictFlexArraysLevelKind">,
1158-
NormalizedValues<["Default", "OneZeroOrIncomplete", "ZeroOrIncomplete"]>,
1158+
NormalizedValues<["Default", "OneZeroOrIncomplete", "ZeroOrIncomplete", "IncompleteOnly"]>,
11591159
HelpText<"Enable optimizations based on the strict definition of flexible arrays">,
11601160
MarshallingInfoEnum<LangOpts<"StrictFlexArraysLevel">, "Default">;
11611161
defm apple_pragma_pack : BoolFOption<"apple-pragma-pack",

clang/lib/AST/Expr.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,11 +214,15 @@ bool Expr::isFlexibleArrayMemberLike(
214214
if (CAT) {
215215
llvm::APInt Size = CAT->getSize();
216216

217+
using FAMKind = LangOptions::StrictFlexArraysLevelKind;
218+
219+
if (StrictFlexArraysLevel == FAMKind::IncompleteOnly)
220+
return false;
221+
217222
// GCC extension, only allowed to represent a FAM.
218223
if (Size == 0)
219224
return true;
220225

221-
using FAMKind = LangOptions::StrictFlexArraysLevelKind;
222226
if (StrictFlexArraysLevel == FAMKind::ZeroOrIncomplete && Size.uge(1))
223227
return false;
224228

clang/lib/AST/ExprConstant.cpp

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11635,17 +11635,31 @@ static bool isUserWritingOffTheEnd(const ASTContext &Ctx, const LValue &LVal) {
1163511635
// conservative with the last element in structs (if it's an array), so our
1163611636
// current behavior is more compatible than an explicit list approach would
1163711637
// be.
11638-
using FAMKind = LangOptions::StrictFlexArraysLevelKind;
11639-
FAMKind StrictFlexArraysLevel = Ctx.getLangOpts().getStrictFlexArraysLevel();
11638+
auto isFlexibleArrayMember = [&] {
11639+
using FAMKind = LangOptions::StrictFlexArraysLevelKind;
11640+
FAMKind StrictFlexArraysLevel =
11641+
Ctx.getLangOpts().getStrictFlexArraysLevel();
11642+
11643+
if (Designator.isMostDerivedAnUnsizedArray())
11644+
return true;
11645+
11646+
if (StrictFlexArraysLevel == FAMKind::Default)
11647+
return true;
11648+
11649+
if (Designator.getMostDerivedArraySize() == 0 &&
11650+
StrictFlexArraysLevel != FAMKind::IncompleteOnly)
11651+
return true;
11652+
11653+
if (Designator.getMostDerivedArraySize() == 1 &&
11654+
StrictFlexArraysLevel == FAMKind::OneZeroOrIncomplete)
11655+
return true;
11656+
11657+
return false;
11658+
};
11659+
1164011660
return LVal.InvalidBase &&
1164111661
Designator.Entries.size() == Designator.MostDerivedPathLength &&
11642-
Designator.MostDerivedIsArrayElement &&
11643-
(Designator.isMostDerivedAnUnsizedArray() ||
11644-
Designator.getMostDerivedArraySize() == 0 ||
11645-
(Designator.getMostDerivedArraySize() == 1 &&
11646-
StrictFlexArraysLevel != FAMKind::Incomplete &&
11647-
StrictFlexArraysLevel != FAMKind::ZeroOrIncomplete) ||
11648-
StrictFlexArraysLevel == FAMKind::Default) &&
11662+
Designator.MostDerivedIsArrayElement && isFlexibleArrayMember() &&
1164911663
isDesignatorAtObjectEnd(Ctx, LVal);
1165011664
}
1165111665

clang/lib/StaticAnalyzer/Core/MemRegion.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -798,7 +798,7 @@ DefinedOrUnknownSVal MemRegionManager::getStaticSize(const MemRegion *MR,
798798
const FAMKind StrictFlexArraysLevel =
799799
Ctx.getLangOpts().getStrictFlexArraysLevel();
800800
if (StrictFlexArraysLevel == FAMKind::ZeroOrIncomplete ||
801-
StrictFlexArraysLevel == FAMKind::Incomplete)
801+
StrictFlexArraysLevel == FAMKind::IncompleteOnly)
802802
return false;
803803

804804
const AnalyzerOptions &Opts = SVB.getAnalyzerOptions();

clang/test/CodeGen/bounds-checking-fam.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
// RUN: %clang_cc1 -emit-llvm -triple x86_64 -fstrict-flex-arrays=1 -fsanitize=array-bounds -x c++ %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-STRICT-1,CXX
66
// RUN: %clang_cc1 -emit-llvm -triple x86_64 -fstrict-flex-arrays=2 -fsanitize=array-bounds %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-STRICT-2
77
// RUN: %clang_cc1 -emit-llvm -triple x86_64 -fstrict-flex-arrays=2 -fsanitize=array-bounds -x c++ %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-STRICT-2,CXX
8+
// RUN: %clang_cc1 -emit-llvm -triple x86_64 -fstrict-flex-arrays=3 -fsanitize=array-bounds %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-STRICT-3
9+
// RUN: %clang_cc1 -emit-llvm -triple x86_64 -fstrict-flex-arrays=3 -fsanitize=array-bounds -x c++ %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-STRICT-3,CXX
810
// Before flexible array member was added to C99, many projects use a
911
// one-element array as the last member of a structure as an alternative.
1012
// E.g. https://github.com/python/cpython/issues/84301
@@ -36,6 +38,7 @@ int test_incomplete(struct Incomplete *p, int i) {
3638
// CHECK-STRICT-0-NOT: @__ubsan
3739
// CHECK-STRICT-1-NOT: @__ubsan
3840
// CHECK-STRICT-2-NOT: @__ubsan
41+
// CHECK-STRICT-3-NOT: @__ubsan
3942
return p->a[i] + (p->a)[i];
4043
}
4144

@@ -44,6 +47,7 @@ int test_zero(struct Zero *p, int i) {
4447
// CHECK-STRICT-0-NOT: @__ubsan
4548
// CHECK-STRICT-1-NOT: @__ubsan
4649
// CHECK-STRICT-2-NOT: @__ubsan
50+
// CHECK-STRICT-3: call void @__ubsan_handle_out_of_bounds_abort(
4751
return p->a[i] + (p->a)[i];
4852
}
4953

@@ -52,6 +56,7 @@ int test_one(struct One *p, int i) {
5256
// CHECK-STRICT-0-NOT: @__ubsan
5357
// CHECK-STRICT-1-NOT: @__ubsan
5458
// CHECK-STRICT-2: call void @__ubsan_handle_out_of_bounds_abort(
59+
// CHECK-STRICT-3: call void @__ubsan_handle_out_of_bounds_abort(
5560
return p->a[i] + (p->a)[i];
5661
}
5762

@@ -68,6 +73,7 @@ int test_three(struct Three *p, int i) {
6873
// CHECK-STRICT-0-NOT: @__ubsan
6974
// CHECK-STRICT-1: call void @__ubsan_handle_out_of_bounds_abort(
7075
// CHECK-STRICT-2: call void @__ubsan_handle_out_of_bounds_abort(
76+
// CHECK-STRICT-3: call void @__ubsan_handle_out_of_bounds_abort(
7177
return p->a[i] + (p->a)[i];
7278
}
7379

@@ -89,6 +95,7 @@ int test_uzero(union uZero *p, int i) {
8995
// CHECK-STRICT-0-NOT: @__ubsan
9096
// CHECK-STRICT-1-NOT: @__ubsan
9197
// CHECK-STRICT-2-NOT: @__ubsan
98+
// CHECK-STRICT-3: call void @__ubsan_handle_out_of_bounds_abort(
9299
return p->a[i] + (p->a)[i];
93100
}
94101

@@ -97,6 +104,7 @@ int test_uone(union uOne *p, int i) {
97104
// CHECK-STRICT-0-NOT: @__ubsan
98105
// CHECK-STRICT-1-NOT: @__ubsan
99106
// CHECK-STRICT-2: call void @__ubsan_handle_out_of_bounds_abort(
107+
// CHECK-STRICT-3: call void @__ubsan_handle_out_of_bounds_abort(
100108
return p->a[i] + (p->a)[i];
101109
}
102110

@@ -105,6 +113,7 @@ int test_utwo(union uTwo *p, int i) {
105113
// CHECK-STRICT-0-NOT: @__ubsan
106114
// CHECK-STRICT-1: call void @__ubsan_handle_out_of_bounds_abort(
107115
// CHECK-STRICT-2: call void @__ubsan_handle_out_of_bounds_abort(
116+
// CHECK-STRICT-3: call void @__ubsan_handle_out_of_bounds_abort(
108117
return p->a[i] + (p->a)[i];
109118
}
110119

@@ -113,6 +122,7 @@ int test_uthree(union uThree *p, int i) {
113122
// CHECK-STRICT-0-NOT: @__ubsan
114123
// CHECK-STRICT-1: call void @__ubsan_handle_out_of_bounds_abort(
115124
// CHECK-STRICT-2: call void @__ubsan_handle_out_of_bounds_abort(
125+
// CHECK-STRICT-3: call void @__ubsan_handle_out_of_bounds_abort(
116126
return p->a[i] + (p->a)[i];
117127
}
118128

@@ -126,6 +136,7 @@ int test_macro(struct Macro *p, int i) {
126136
// CHECK-STRICT-0-NOT: @__ubsan
127137
// CHECK-STRICT-1-NOT: @__ubsan
128138
// CHECK-STRICT-2: call void @__ubsan_handle_out_of_bounds_abort(
139+
// CHECK-STRICT-3: call void @__ubsan_handle_out_of_bounds_abort(
129140
return p->a[i] + (p->a)[i];
130141
}
131142

clang/test/CodeGen/object-size-flex-array.c

Lines changed: 70 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
// RUN: %clang -fstrict-flex-arrays=2 -target x86_64-apple-darwin -S -emit-llvm %s -o - 2>&1 | FileCheck --check-prefixes=CHECK,CHECK-STRICT-2 %s
2-
// RUN: %clang -fstrict-flex-arrays=1 -target x86_64-apple-darwin -S -emit-llvm %s -o - 2>&1 | FileCheck --check-prefixes=CHECK,CHECK-STRICT-1 %s
3-
// RUN: %clang -fstrict-flex-arrays=0 -target x86_64-apple-darwin -S -emit-llvm %s -o - 2>&1 | FileCheck --check-prefixes=CHECK,CHECK-STRICT-0 %s
1+
// RUN: %clang -target x86_64 -O2 -S -emit-llvm %s -o - 2>&1 | FileCheck --check-prefixes=CHECK,CHECK-NO-STRICT %s
2+
// RUN: %clang -fstrict-flex-arrays=0 -target x86_64 -O2 -S -emit-llvm %s -o - 2>&1 | FileCheck --check-prefixes=CHECK,CHECK-STRICT-0 %s
3+
// RUN: %clang -fstrict-flex-arrays=1 -target x86_64 -O2 -S -emit-llvm %s -o - 2>&1 | FileCheck --check-prefixes=CHECK,CHECK-STRICT-1 %s
4+
// RUN: %clang -fstrict-flex-arrays=2 -target x86_64 -O2 -S -emit-llvm %s -o - 2>&1 | FileCheck --check-prefixes=CHECK,CHECK-STRICT-2 %s
5+
// RUN: %clang -fstrict-flex-arrays=3 -target x86_64 -O2 -S -emit-llvm %s -o - 2>&1 | FileCheck --check-prefixes=CHECK,CHECK-STRICT-3 %s
46

57
#define OBJECT_SIZE_BUILTIN __builtin_object_size
68

@@ -26,36 +28,86 @@ typedef struct {
2628

2729
// CHECK-LABEL: @bar(
2830
unsigned bar(foo_t *f) {
29-
// CHECK-STRICT-0: ret i32 %
30-
// CHECK-STRICT-1: ret i32 %
31-
// CHECK-STRICT-2: ret i32 %
31+
// CHECK-NO-STRICT: ret i32 -1
32+
// CHECK-STRICT-0: ret i32 -1
33+
// CHECK-STRICT-1: ret i32 -1
34+
// CHECK-STRICT-2: ret i32 -1
35+
// CHECK-STRICT-3: ret i32 -1
3236
return OBJECT_SIZE_BUILTIN(f->c, 1);
3337
}
3438

3539
// CHECK-LABEL: @bar0(
3640
unsigned bar0(foo0_t *f) {
37-
// CHECK-STRICT-0: ret i32 %
38-
// CHECK-STRICT-1: ret i32 %
39-
// CHECK-STRICT-2: ret i32 %
41+
// CHECK-NO-STRICT: ret i32 -1
42+
// CHECK-STRICT-0: ret i32 -1
43+
// CHECK-STRICT-1: ret i32 -1
44+
// CHECK-STRICT-2: ret i32 -1
45+
// CHECK-STRICT-3: ret i32 0
4046
return OBJECT_SIZE_BUILTIN(f->c, 1);
4147
}
4248

4349
// CHECK-LABEL: @bar1(
4450
unsigned bar1(foo1_t *f) {
45-
// CHECK-STRICT-0: ret i32 %
46-
// CHECK-STRICT-1: ret i32 %
51+
// CHECK-NO-STRICT: ret i32 -1
52+
// CHECK-STRICT-0: ret i32 -1
53+
// CHECK-STRICT-1: ret i32 -1
4754
// CHECK-STRICT-2: ret i32 8
55+
// CHECK-STRICT-3: ret i32 8
4856
return OBJECT_SIZE_BUILTIN(f->c, 1);
4957
}
5058

5159
// CHECK-LABEL: @bar2(
5260
unsigned bar2(foo2_t *f) {
53-
// CHECK-STRICT-0: ret i32 %
61+
// CHECK-NO-STRICT: ret i32 -1
62+
// CHECK-STRICT-0: ret i32 -1
5463
// CHECK-STRICT-1: ret i32 16
5564
// CHECK-STRICT-2: ret i32 16
65+
// CHECK-STRICT-3: ret i32 16
5666
return OBJECT_SIZE_BUILTIN(f->c, 1);
5767
}
5868

69+
#define DYNAMIC_OBJECT_SIZE_BUILTIN __builtin_dynamic_object_size
70+
71+
// CHECK-LABEL: @dyn_bar(
72+
unsigned dyn_bar(foo_t *f) {
73+
// CHECK-NO-STRICT: ret i32 -1
74+
// CHECK-STRICT-0: ret i32 -1
75+
// CHECK-STRICT-1: ret i32 -1
76+
// CHECK-STRICT-2: ret i32 -1
77+
// CHECK-STRICT-3: ret i32 -1
78+
return DYNAMIC_OBJECT_SIZE_BUILTIN(f->c, 1);
79+
}
80+
81+
// CHECK-LABEL: @dyn_bar0(
82+
unsigned dyn_bar0(foo0_t *f) {
83+
// CHECK-NO-STRICT: ret i32 -1
84+
// CHECK-STRICT-0: ret i32 -1
85+
// CHECK-STRICT-1: ret i32 -1
86+
// CHECK-STRICT-2: ret i32 -1
87+
// CHECK-STRICT-3: ret i32 0
88+
return DYNAMIC_OBJECT_SIZE_BUILTIN(f->c, 1);
89+
}
90+
91+
// CHECK-LABEL: @dyn_bar1(
92+
unsigned dyn_bar1(foo1_t *f) {
93+
// CHECK-NO-STRICT: ret i32 -1
94+
// CHECK-STRICT-0: ret i32 -1
95+
// CHECK-STRICT-1: ret i32 -1
96+
// CHECK-STRICT-2: ret i32 8
97+
// CHECK-STRICT-3: ret i32 8
98+
return DYNAMIC_OBJECT_SIZE_BUILTIN(f->c, 1);
99+
}
100+
101+
// CHECK-LABEL: @dyn_bar2(
102+
unsigned dyn_bar2(foo2_t *f) {
103+
// CHECK-NO-STRICT: ret i32 -1
104+
// CHECK-STRICT-0: ret i32 -1
105+
// CHECK-STRICT-1: ret i32 16
106+
// CHECK-STRICT-2: ret i32 16
107+
// CHECK-STRICT-3: ret i32 16
108+
return DYNAMIC_OBJECT_SIZE_BUILTIN(f->c, 1);
109+
}
110+
59111
// Also checks for non-trailing flex-array like members
60112

61113
typedef struct {
@@ -75,24 +127,30 @@ typedef struct {
75127

76128
// CHECK-LABEL: @babar0(
77129
unsigned babar0(foofoo0_t *f) {
130+
// CHECK-NO-STRICT: ret i32 0
78131
// CHECK-STRICT-0: ret i32 0
79132
// CHECK-STRICT-1: ret i32 0
80133
// CHECK-STRICT-2: ret i32 0
134+
// CHECK-STRICT-3: ret i32 0
81135
return OBJECT_SIZE_BUILTIN(f->c, 1);
82136
}
83137

84138
// CHECK-LABEL: @babar1(
85139
unsigned babar1(foofoo1_t *f) {
140+
// CHECK-NO-STRICT: ret i32 8
86141
// CHECK-STRICT-0: ret i32 8
87142
// CHECK-STRICT-1: ret i32 8
88143
// CHECK-STRICT-2: ret i32 8
144+
// CHECK-STRICT-3: ret i32 8
89145
return OBJECT_SIZE_BUILTIN(f->c, 1);
90146
}
91147

92148
// CHECK-LABEL: @babar2(
93149
unsigned babar2(foofoo2_t *f) {
150+
// CHECK-NO-STRICT: ret i32 16
94151
// CHECK-STRICT-0: ret i32 16
95152
// CHECK-STRICT-1: ret i32 16
96153
// CHECK-STRICT-2: ret i32 16
154+
// CHECK-STRICT-3: ret i32 16
97155
return OBJECT_SIZE_BUILTIN(f->c, 1);
98156
}

clang/test/Sema/array-bounds-ptr-arith.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// RUN: %clang_cc1 -verify=expected -Warray-bounds-pointer-arithmetic %s
22
// RUN: %clang_cc1 -verify=expected -Warray-bounds-pointer-arithmetic %s -fstrict-flex-arrays=0
33
// RUN: %clang_cc1 -verify=expected,strict -Warray-bounds-pointer-arithmetic %s -fstrict-flex-arrays=2
4+
// RUN: %clang_cc1 -verify=expected,strict -Warray-bounds-pointer-arithmetic %s -fstrict-flex-arrays=3
45

56
// Test case from PR10615
67
struct ext2_super_block{

clang/test/SemaCXX/array-bounds-strict-flex-arrays.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
// RUN: %clang_cc1 -verify=relaxed -fstrict-flex-arrays=1 %s
2-
// RUN: %clang_cc1 -verify=relaxed,strict -fstrict-flex-arrays=2 %s
1+
// RUN: %clang_cc1 -verify=relaxed -fstrict-flex-arrays=1 %s
2+
// RUN: %clang_cc1 -verify=relaxed,strict -fstrict-flex-arrays=2 %s
3+
// RUN: %clang_cc1 -verify=relaxed,strict,very-strict -fstrict-flex-arrays=3 %s
34

45
// We cannot know for sure the size of a flexible array.
56
struct t {
@@ -10,7 +11,7 @@ void test(t *s2) {
1011
s2->a[2] = 0; // no-warning
1112
}
1213

13-
// Under -fstrict-flex-arrays={1,2} `a` is not a flexible array
14+
// Under -fstrict-flex-arrays={1,2,3} `a` is not a flexible array
1415
struct t0 {
1516
int f;
1617
int a[10]; // relaxed-note {{array 'a' declared here}}
@@ -29,11 +30,11 @@ void test1(t1 *s2) {
2930
s2->a[2] = 0; // strict-warning {{array index 2 is past the end of the array (that has type 'int[1]')}}
3031
}
3132

32-
// Under -fstrict-flex-arrays={1,2} `a` is a flexible array.
33+
// Under -fstrict-flex-arrays={1,2} `a` is a flexible array, but not under -fstrict-flex-arrays=3.
3334
struct t2 {
3435
int f;
35-
int a[0];
36+
int a[0]; // very-strict-note {{array 'a' declared here}}
3637
};
3738
void test1(t2 *s2) {
38-
s2->a[2] = 0; // no-warning
39+
s2->a[2] = 0; // very-strict-warning {{array index 2 is past the end of the array (that has type 'int[0]')}}
3940
}

0 commit comments

Comments
 (0)