diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1143,7 +1143,7 @@ def fapple_kext : Flag<["-"], "fapple-kext">, Group, Flags<[CC1Option]>, HelpText<"Use Apple's kernel extensions ABI">, MarshallingInfoFlag>; -def fstrict_flex_arrays_EQ : Joined<["-"], "fstrict-flex-arrays=">,Group, +def fstrict_flex_arrays_EQ : Joined<["-"], "fstrict-flex-arrays=">, Group, MetaVarName<"">, Values<"0,1,2">, LangOpts<"StrictFlexArrays">, Flags<[CC1Option]>, diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -906,10 +906,8 @@ if (const auto *FD = dyn_cast(ME->getMemberDecl())) { // FIXME: Sema doesn't treat a T[1] union member as a flexible array // member, only a T[0] or T[] member gets that treatment. - // Under StrictFlexArraysLevel, obey c99+ that disallows FAM in union, see - // C11 6.7.2.1 ยง18 if (FD->getParent()->isUnion()) - return StrictFlexArraysLevel < 2; + return true; RecordDecl::field_iterator FI( DeclContext::decl_iterator(const_cast(FD))); return ++FI == FD->getParent()->field_end(); diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -15888,16 +15888,10 @@ if (!ND) return false; - if (StrictFlexArraysLevel >= 2 && Size != 0) - return false; - - if (StrictFlexArraysLevel == 1 && Size.uge(2)) - return false; - // FIXME: While the default -fstrict-flex-arrays=0 permits Size>1 trailing // arrays to be treated as flexible-array-members, we still emit diagnostics // as if they are not. Pending further discussion... - if (StrictFlexArraysLevel == 0 && Size != 1) + if (StrictFlexArraysLevel >= 2 || Size.uge(2)) return false; const FieldDecl *FD = dyn_cast(ND); @@ -16065,8 +16059,8 @@ if (BaseType->isIncompleteType()) return; - // FIXME: this check should belong to the IsTailPaddedMemberArray call - // below. + // FIXME: this check should be used to set IsUnboundedArray from the + // beginning. llvm::APInt size = ArrayTy->getSize(); if (!size.isStrictlyPositive()) return; diff --git a/clang/test/CodeGen/bounds-checking-fam.c b/clang/test/CodeGen/bounds-checking-fam.c --- a/clang/test/CodeGen/bounds-checking-fam.c +++ b/clang/test/CodeGen/bounds-checking-fam.c @@ -35,6 +35,51 @@ return p->a[i] + (p->a)[i]; } +union uZero { + int a[0]; +}; +union uOne { + int a[1]; +}; +union uTwo { + int a[2]; +}; +union uThree { + int a[3]; +}; + +// CHECK-LABEL: define {{.*}} @{{.*}}test_uzero{{.*}}( +int test_uzero(union uZero *p, int i) { + // CHECK-STRICT-0-NOT: @__ubsan + // CHECK-STRICT-1-NOT: @__ubsan + // CHECK-STRICT-2-NOT: @__ubsan + return p->a[i] + (p->a)[i]; +} + +// CHECK-LABEL: define {{.*}} @{{.*}}test_uone{{.*}}( +int test_uone(union uOne *p, int i) { + // CHECK-STRICT-0-NOT: @__ubsan + // CHECK-STRICT-1-NOT: @__ubsan + // CHECK-STRICT-2: @__ubsan + return p->a[i] + (p->a)[i]; +} + +// CHECK-LABEL: define {{.*}} @{{.*}}test_utwo{{.*}}( +int test_utwo(union uTwo *p, int i) { + // CHECK-STRICT-0: @__ubsan + // CHECK-STRICT-1: @__ubsan + // CHECK-STRICT-2: @__ubsan + return p->a[i] + (p->a)[i]; +} + +// CHECK-LABEL: define {{.*}} @{{.*}}test_uthree{{.*}}( +int test_uthree(union uThree *p, int i) { + // CHECK-STRICT-0: @__ubsan + // CHECK-STRICT-1: @__ubsan + // CHECK-STRICT-2: @__ubsan + return p->a[i] + (p->a)[i]; +} + // CHECK-LABEL: define {{.*}} @{{.*}}test_three{{.*}}( int test_three(struct Three *p, int i) { // CHECK-STRICT-0: call void @__ubsan_handle_out_of_bounds_abort( diff --git a/clang/test/CodeGen/object-size-flex-array.c b/clang/test/CodeGen/object-size-flex-array.c --- a/clang/test/CodeGen/object-size-flex-array.c +++ b/clang/test/CodeGen/object-size-flex-array.c @@ -24,7 +24,7 @@ double c[2]; } foo2_t; -// CHECK-LABEL: @bar +// CHECK-LABEL: @bar( unsigned bar(foo_t *f) { // CHECK-STRICT-0: ret i32 % // CHECK-STRICT-1: ret i32 % @@ -32,7 +32,7 @@ return OBJECT_SIZE_BUILTIN(f->c, 1); } -// CHECK-LABEL: @bar0 +// CHECK-LABEL: @bar0( unsigned bar0(foo0_t *f) { // CHECK-STRICT-0: ret i32 % // CHECK-STRICT-1: ret i32 % @@ -40,7 +40,7 @@ return OBJECT_SIZE_BUILTIN(f->c, 1); } -// CHECK-LABEL: @bar1 +// CHECK-LABEL: @bar1( unsigned bar1(foo1_t *f) { // CHECK-STRICT-0: ret i32 % // CHECK-STRICT-1: ret i32 % @@ -48,7 +48,7 @@ return OBJECT_SIZE_BUILTIN(f->c, 1); } -// CHECK-LABEL: @bar2 +// CHECK-LABEL: @bar2( unsigned bar2(foo2_t *f) { // CHECK-STRICT-0: ret i32 % // CHECK-STRICT-1: ret i32 16 @@ -73,7 +73,7 @@ float f; } foofoo2_t; -// CHECK-LABEL: @babar0 +// CHECK-LABEL: @babar0( unsigned babar0(foofoo0_t *f) { // CHECK-STRICT-0: ret i32 0 // CHECK-STRICT-1: ret i32 0 @@ -81,7 +81,7 @@ return OBJECT_SIZE_BUILTIN(f->c, 1); } -// CHECK-LABEL: @babar1 +// CHECK-LABEL: @babar1( unsigned babar1(foofoo1_t *f) { // CHECK-STRICT-0: ret i32 8 // CHECK-STRICT-1: ret i32 8 @@ -89,7 +89,7 @@ return OBJECT_SIZE_BUILTIN(f->c, 1); } -// CHECK-LABEL: @babar2 +// CHECK-LABEL: @babar2( unsigned babar2(foofoo2_t *f) { // CHECK-STRICT-0: ret i32 16 // CHECK-STRICT-1: ret i32 16