diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -365,6 +365,17 @@ All, }; + enum class StrictFlexArraysLevelKind { + /// Any trailing array member is a FAM. + Default = 0, + /// Any trailing array member of undefined, 0, or 1 size is a FAM. + OneZeroOrIncomplete = 1, + /// Any trailing array member of undefined or 0 size is a FAM. + ZeroOrIncomplete = 2, + /// Any trailing array member of undefined size is a FAM. + Incomplete = 3, + }; + public: /// The used language standard. LangStandard::Kind LangStd; 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 @@ -427,7 +427,10 @@ LANGOPT(RegisterStaticDestructors, 1, 1, "Register C++ static destructors") LANGOPT(MatrixTypes, 1, 0, "Enable or disable the builtin matrix type") -LANGOPT(StrictFlexArrays, 2, 0, "Rely on strict definition of flexible arrays") + +ENUM_LANGOPT(StrictFlexArraysLevel, StrictFlexArraysLevelKind, 2, + StrictFlexArraysLevelKind::Default, + "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 @@ -1149,10 +1149,12 @@ MarshallingInfoFlag>; def fstrict_flex_arrays_EQ : Joined<["-"], "fstrict-flex-arrays=">, Group, MetaVarName<"">, Values<"0,1,2">, - LangOpts<"StrictFlexArrays">, + LangOpts<"StrictFlexArraysLevel">, Flags<[CC1Option]>, + NormalizedValuesScope<"LangOptions::StrictFlexArraysLevelKind">, + NormalizedValues<["Default", "OneZeroOrIncomplete", "ZeroOrIncomplete", "Incomplete"]>, HelpText<"Enable optimizations based on the strict definition of flexible arrays">, - MarshallingInfoInt>; + MarshallingInfoEnum, "Default">; 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 @@ -11613,15 +11613,17 @@ // conservative with the last element in structs (if it's an array), so our // current behavior is more compatible than an explicit list approach would // be. - int StrictFlexArraysLevel = Ctx.getLangOpts().StrictFlexArrays; + using FAMKind = LangOptions::StrictFlexArraysLevelKind; + FAMKind StrictFlexArraysLevel = Ctx.getLangOpts().getStrictFlexArraysLevel(); return LVal.InvalidBase && Designator.Entries.size() == Designator.MostDerivedPathLength && Designator.MostDerivedIsArrayElement && (Designator.isMostDerivedAnUnsizedArray() || Designator.getMostDerivedArraySize() == 0 || (Designator.getMostDerivedArraySize() == 1 && - StrictFlexArraysLevel < 2) || - StrictFlexArraysLevel == 0) && + StrictFlexArraysLevel != FAMKind::Incomplete && + StrictFlexArraysLevel != FAMKind::ZeroOrIncomplete) || + StrictFlexArraysLevel == FAMKind::Default) && isDesignatorAtObjectEnd(Ctx, LVal); } 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 @@ -878,16 +878,20 @@ /// Determine whether this expression refers to a flexible array member in a /// struct. We disable array bounds checks for such members. static bool isFlexibleArrayMemberExpr(const Expr *E, - unsigned StrictFlexArraysLevel) { + LangOptions::StrictFlexArraysLevelKind + StrictFlexArraysLevel) { // For compatibility with existing code, we treat arrays of length 0 or // 1 as flexible array members. // FIXME: This is inconsistent with the warning code in SemaChecking. Unify // the two mechanisms. const ArrayType *AT = E->getType()->castAsArrayTypeUnsafe(); if (const auto *CAT = dyn_cast(AT)) { + using FAMKind = LangOptions::StrictFlexArraysLevelKind; + // FIXME: Sema doesn't treat [1] as a flexible array member if the bound // was produced by macro expansion. - if (StrictFlexArraysLevel >= 2 && CAT->getSize().ugt(0)) + if (StrictFlexArraysLevel == FAMKind::ZeroOrIncomplete && + CAT->getSize().ugt(0)) 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 ubsan @@ -963,7 +967,8 @@ static llvm::Value *getArrayIndexingBound(CodeGenFunction &CGF, const Expr *Base, QualType &IndexedType, - unsigned StrictFlexArraysLevel) { + LangOptions::StrictFlexArraysLevelKind + StrictFlexArraysLevel) { // For the vector indexing extension, the bound is the number of elements. if (const VectorType *VT = Base->getType()->getAs()) { IndexedType = Base->getType(); @@ -1001,7 +1006,8 @@ "should not be called unless adding bounds checks"); SanitizerScope SanScope(this); - const unsigned StrictFlexArraysLevel = getLangOpts().StrictFlexArrays; + const LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel = + getLangOpts().getStrictFlexArraysLevel(); QualType IndexedType; llvm::Value *Bound = 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 @@ -15904,7 +15904,8 @@ /// We avoid emitting out-of-bounds access warnings for such arrays. static bool isFlexibleArrayMemberExpr(Sema &S, const Expr *E, const NamedDecl *ND, - unsigned StrictFlexArraysLevel) { + LangOptions::StrictFlexArraysLevelKind + StrictFlexArraysLevel) { if (!ND) return false; @@ -15919,7 +15920,9 @@ // 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 >= 2 || Size.uge(2)) + using FAMKind = LangOptions::StrictFlexArraysLevelKind; + if (StrictFlexArraysLevel == FAMKind::ZeroOrIncomplete || + Size.uge(2)) return false; const FieldDecl *FD = dyn_cast(ND); @@ -15981,7 +15984,8 @@ const ConstantArrayType *ArrayTy = Context.getAsConstantArrayType(BaseExpr->getType()); - unsigned StrictFlexArraysLevel = getLangOpts().StrictFlexArrays; + LangOptions::StrictFlexArraysLevelKind + StrictFlexArraysLevel = getLangOpts().getStrictFlexArraysLevel(); const NamedDecl *ND = nullptr; if (const auto *DRE = dyn_cast(BaseExpr)) diff --git a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp --- a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp +++ b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp @@ -794,7 +794,11 @@ if (Size.isZero()) return true; - if (getContext().getLangOpts().StrictFlexArrays >= 2) + using FAMKind = LangOptions::StrictFlexArraysLevelKind; + const FAMKind StrictFlexArraysLevel = + getContext().getLangOpts().getStrictFlexArraysLevel(); + if (StrictFlexArraysLevel == FAMKind::ZeroOrIncomplete || + StrictFlexArraysLevel == FAMKind::Incomplete) return false; const AnalyzerOptions &Opts = SVB.getAnalyzerOptions();