diff --git a/clang/docs/ClangCommandLineReference.rst b/clang/docs/ClangCommandLineReference.rst --- a/clang/docs/ClangCommandLineReference.rst +++ b/clang/docs/ClangCommandLineReference.rst @@ -2621,6 +2621,10 @@ .. option:: -fuse-init-array, -fno-use-init-array +.. option:: -fstrict-flex-array + +Do not consider sized arrays at the end of a struct as flexible arrays. + .. option:: -fuse-ld= .. option:: -fuse-line-directives, -fno-use-line-directives diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -68,6 +68,11 @@ Randomizing structure layout is a C-only feature. +- Clang now supports the ``-fstrict-flex-arrays`` to only consider trailing + arrays with unknown size arrays as flexible arrays. This breaks compatibility + with some legacy code but allows for better folding of + ``__builtin_object_size``. + Bug Fixes --------- - ``CXXNewExpr::getArraySize()`` previously returned a ``llvm::Optional`` diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -422,6 +422,7 @@ LANGOPT(RegisterStaticDestructors, 1, 1, "Register C++ static destructors") LANGOPT(MatrixTypes, 1, 0, "Enable or disable the builtin matrix type") +LANGOPT(StrictFlexArrays, 1, 0, "Rely on strict definition of flexible arrays") COMPATIBLE_VALUE_LANGOPT(MaxTokens, 32, 0, "Max number of tokens per TU or 0") 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 @@ -1132,6 +1132,10 @@ def fapple_kext : Flag<["-"], "fapple-kext">, Group, Flags<[CC1Option]>, HelpText<"Use Apple's kernel extensions ABI">, MarshallingInfoFlag>; +defm strict_flex_arrays : BoolFOption<"strict-flex-arrays", + LangOpts<"StrictFlexArrays">, DefaultFalse, + PosFlag, + NegFlag>; defm apple_pragma_pack : BoolFOption<"apple-pragma-pack", LangOpts<"ApplePragmaPack">, DefaultFalse, PosFlag, 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 @@ -11600,6 +11600,8 @@ return LVal.InvalidBase && Designator.Entries.size() == Designator.MostDerivedPathLength && Designator.MostDerivedIsArrayElement && + (Designator.isMostDerivedAnUnsizedArray() || + !Ctx.getLangOpts().StrictFlexArrays) && isDesignatorAtObjectEnd(Ctx, LVal); } diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -6214,6 +6214,9 @@ Args.AddLastArg(CmdArgs, options::OPT_funroll_loops, options::OPT_fno_unroll_loops); + Args.addOptInFlag(CmdArgs, options::OPT_fstrict_flex_arrays, + options::OPT_fno_strict_flex_arrays); + Args.AddLastArg(CmdArgs, options::OPT_pthread); if (Args.hasFlag(options::OPT_mspeculative_load_hardening, diff --git a/clang/test/CodeGen/object-size-flex-array.c b/clang/test/CodeGen/object-size-flex-array.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/object-size-flex-array.c @@ -0,0 +1,60 @@ +// RUN: %clang -fstrict-flex-arrays -target x86_64-apple-darwin -S -emit-llvm %s -o - 2>&1 | FileCheck --check-prefix CHECK-STRICT %s +// RUN: %clang -fno-strict-flex-arrays -target x86_64-apple-darwin -S -emit-llvm %s -o - 2>&1 | FileCheck %s + +#ifndef DYNAMIC +#define OBJECT_SIZE_BUILTIN __builtin_object_size +#else +#define OBJECT_SIZE_BUILTIN __builtin_dynamic_object_size +#endif + +typedef struct { + float f; + double c[]; +} foo_t; + +typedef struct { + float f; + double c[0]; +} foo0_t; + +typedef struct { + float f; + double c[1]; +} foo1_t; + +typedef struct { + float f; + double c[2]; +} foo2_t; + +// CHECK-LABEL: @bar +// CHECK-STRICT-LABEL: @bar +unsigned bar(foo_t *f) { + // CHECK: ret i32 % + // CHECK-STRICT: ret i32 % + return OBJECT_SIZE_BUILTIN(f->c, 1); +} + +// CHECK-LABEL: @bar0 +// CHECK-STRICT-LABEL: @bar +unsigned bar0(foo0_t *f) { + // CHECK: ret i32 % + // CHECK-STRICT: ret i32 0 + return OBJECT_SIZE_BUILTIN(f->c, 1); +} + +// CHECK-LABEL: @bar1 +// CHECK-STRICT-LABEL: @bar +unsigned bar1(foo1_t *f) { + // CHECK: ret i32 % + // CHECK-STRICT: ret i32 8 + return OBJECT_SIZE_BUILTIN(f->c, 1); +} + +// CHECK-LABEL: @bar2 +// CHECK-STRICT-LABEL: @bar +unsigned bar2(foo2_t *f) { + // CHECK: ret i32 % + // CHECK-STRICT: ret i32 16 + return OBJECT_SIZE_BUILTIN(f->c, 1); +}