diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -528,7 +528,8 @@ /// When IgnoreTemplateOrMacroSubstitution is set, it doesn't consider sizes /// resulting from the substitution of a macro or a template as special sizes. bool isFlexibleArrayMemberLike( - ASTContext &Context, unsigned StrictFlexArraysLevel, + ASTContext &Context, + LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel, bool IgnoreTemplateOrMacroSubstitution = false) const; /// isIntegerConstantExpr - Return the value if this expression is a valid 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/Expr.cpp b/clang/lib/AST/Expr.cpp --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -204,7 +204,8 @@ } bool Expr::isFlexibleArrayMemberLike( - ASTContext &Context, unsigned StrictFlexArraysLevel, + ASTContext &Context, + LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel, bool IgnoreTemplateOrMacroSubstitution) const { // For compatibility with existing code, we treat arrays of length 0 or @@ -219,7 +220,8 @@ // 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; } else if (!Context.getAsIncompleteArrayType(getType())) 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 @@ -919,7 +919,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(); @@ -958,7 +959,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 @@ -15915,7 +15915,8 @@ const ConstantArrayType *ArrayTy = Context.getAsConstantArrayType(BaseExpr->getType()); - unsigned StrictFlexArraysLevel = getLangOpts().StrictFlexArrays; + LangOptions::StrictFlexArraysLevelKind + StrictFlexArraysLevel = getLangOpts().getStrictFlexArraysLevel(); const Type *BaseType = ArrayTy == nullptr ? nullptr : ArrayTy->getElementType().getTypePtr(); 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 = + Ctx.getLangOpts().getStrictFlexArraysLevel(); + if (StrictFlexArraysLevel == FAMKind::ZeroOrIncomplete || + StrictFlexArraysLevel == FAMKind::Incomplete) return false; const AnalyzerOptions &Opts = SVB.getAnalyzerOptions();