Skip to content

Commit cdfa15d

Browse files
committed
Revert "[clang] Introduce -fstrict-flex-arrays=<n> for stricter handling of flexible arrays"
This reverts D126864 and related fixes. This reverts commit 572b087. This reverts commit 886715a.
1 parent 1bdbf13 commit cdfa15d

File tree

18 files changed

+176
-309
lines changed

18 files changed

+176
-309
lines changed

clang/docs/ClangCommandLineReference.rst

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2639,12 +2639,6 @@ Enable unstable and experimental features
26392639

26402640
.. option:: -fuse-init-array, -fno-use-init-array
26412641

2642-
.. option:: -fstrict-flex-arrays=<arg>, -fno-strict-flex-arrays
2643-
2644-
Control which arrays are considered as flexible arrays members. <arg>
2645-
can be 1 (array of size 0, 1 and undefined are considered), 2 (array of size 0
2646-
and undefined are considered) or 3 (only array of undefined size are considered).
2647-
26482642
.. option:: -fuse-ld=<arg>
26492643

26502644
.. option:: -fuse-line-directives, -fno-use-line-directives

clang/docs/ReleaseNotes.rst

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,16 +68,11 @@ Major New Features
6868

6969
Randomizing structure layout is a C-only feature.
7070

71-
- Clang now supports the ``-fstrict-flex-arrays=<arg>`` option to control which
72-
array bounds lead to flexible array members. The option yields more accurate
73-
``__builtin_object_size`` and ``__builtin_dynamic_object_size`` results in
74-
most cases but may be overly conservative for some legacy code.
7571
- Experimental support for HLSL has been added. The implementation is
7672
incomplete and highly experimental. For more information about the ongoing
7773
work to support HLSL see the `documentation
7874
<https://clang.llvm.org/docs/HLSLSupport.html>`_, or the `GitHub project
7975
<https://github.com/orgs/llvm/projects/4>`_.
80-
8176
Bug Fixes
8277
---------
8378
- ``CXXNewExpr::getArraySize()`` previously returned a ``llvm::Optional``

clang/include/clang/AST/Expr.h

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -443,16 +443,6 @@ class Expr : public ValueStmt {
443443
return (OK == OK_Ordinary || OK == OK_BitField);
444444
}
445445

446-
/// True when this expression refers to a flexible array member in a
447-
/// struct. \c StrictFlexArraysLevel controls which array bounds are
448-
/// acceptable for such arrays:
449-
///
450-
/// - 0 => any array bound,
451-
/// - 1 => [0], [1], [ ]
452-
/// - 2 => [0], [ ]
453-
/// - 3 => [ ]
454-
bool isFlexibleArrayMember(ASTContext &Ctx, int StrictFlexArraysLevel) const;
455-
456446
/// setValueKind - Set the value kind produced by this expression.
457447
void setValueKind(ExprValueKind Cat) { ExprBits.ValueKind = Cat; }
458448

clang/include/clang/Basic/LangOptions.def

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -424,7 +424,6 @@ LANGOPT(PaddingOnUnsignedFixedPoint, 1, 0,
424424
LANGOPT(RegisterStaticDestructors, 1, 1, "Register C++ static destructors")
425425

426426
LANGOPT(MatrixTypes, 1, 0, "Enable or disable the builtin matrix type")
427-
LANGOPT(StrictFlexArrays, 2, 0, "Rely on strict definition of flexible arrays")
428427

429428
COMPATIBLE_VALUE_LANGOPT(MaxTokens, 32, 0, "Max number of tokens per TU or 0")
430429

clang/include/clang/Driver/Options.td

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1140,12 +1140,6 @@ def fallow_unsupported : Flag<["-"], "fallow-unsupported">, Group<f_Group>;
11401140
def fapple_kext : Flag<["-"], "fapple-kext">, Group<f_Group>, Flags<[CC1Option]>,
11411141
HelpText<"Use Apple's kernel extensions ABI">,
11421142
MarshallingInfoFlag<LangOpts<"AppleKext">>;
1143-
def fstrict_flex_arrays_EQ : Joined<["-"], "fstrict-flex-arrays=">,Group<f_Group>,
1144-
MetaVarName<"<n>">, Values<"0,1,2,3">,
1145-
LangOpts<"StrictFlexArrays">,
1146-
Flags<[CC1Option]>,
1147-
HelpText<"Enable optimizations based on the strict definition of flexible arrays">,
1148-
MarshallingInfoInt<LangOpts<"StrictFlexArrays">>;
11491143
defm apple_pragma_pack : BoolFOption<"apple-pragma-pack",
11501144
LangOpts<"ApplePragmaPack">, DefaultFalse,
11511145
PosFlag<SetTrue, [CC1Option], "Enable Apple gcc-compatible #pragma pack handling">,

clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1364,7 +1364,6 @@ class MemRegionManager {
13641364
~MemRegionManager();
13651365

13661366
ASTContext &getContext() { return Ctx; }
1367-
const ASTContext &getContext() const { return Ctx; }
13681367

13691368
llvm::BumpPtrAllocator &getAllocator() { return A; }
13701369

clang/lib/AST/Expr.cpp

Lines changed: 0 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -203,91 +203,6 @@ bool Expr::isKnownToHaveBooleanValue(bool Semantic) const {
203203
return false;
204204
}
205205

206-
bool Expr::isFlexibleArrayMember(ASTContext &Ctx,
207-
int StrictFlexArraysLevel) const {
208-
const NamedDecl *ND = nullptr;
209-
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(this))
210-
ND = DRE->getDecl();
211-
if (const MemberExpr *ME = dyn_cast<MemberExpr>(this))
212-
ND = ME->getMemberDecl();
213-
if (const ObjCIvarRefExpr *RE = dyn_cast<ObjCIvarRefExpr>(this))
214-
ND = RE->getDecl();
215-
if (!ND)
216-
return false;
217-
218-
const ConstantArrayType *ArrayTy = Ctx.getAsConstantArrayType(getType());
219-
220-
const Type *BaseType =
221-
ArrayTy == nullptr ? nullptr : ArrayTy->getElementType().getTypePtr();
222-
bool IsUnboundedArray = (BaseType == nullptr);
223-
224-
if (!IsUnboundedArray) {
225-
llvm::APInt Size = ArrayTy->getSize();
226-
227-
switch (StrictFlexArraysLevel) {
228-
case 3:
229-
return false;
230-
case 2:
231-
if (Size != 0)
232-
return false;
233-
break;
234-
case 1:
235-
if (Size.ugt(1))
236-
return false;
237-
break;
238-
case 0:
239-
break;
240-
default:
241-
llvm_unreachable("Invalid strict flex arrays level");
242-
}
243-
}
244-
245-
const FieldDecl *FD = dyn_cast<FieldDecl>(ND);
246-
if (!FD)
247-
return false;
248-
249-
// Don't consider sizes resulting from macro expansions or template argument
250-
// substitution to form C89 tail-padded arrays.
251-
252-
TypeSourceInfo *TInfo = FD->getTypeSourceInfo();
253-
while (TInfo) {
254-
TypeLoc TL = TInfo->getTypeLoc();
255-
// Look through typedefs.
256-
if (TypedefTypeLoc TTL = TL.getAs<TypedefTypeLoc>()) {
257-
const TypedefNameDecl *TDL = TTL.getTypedefNameDecl();
258-
TInfo = TDL->getTypeSourceInfo();
259-
continue;
260-
}
261-
if (ConstantArrayTypeLoc CTL = TL.getAs<ConstantArrayTypeLoc>()) {
262-
const Expr *SizeExpr = dyn_cast<IntegerLiteral>(CTL.getSizeExpr());
263-
if (!SizeExpr || SizeExpr->getExprLoc().isMacroID())
264-
return false;
265-
}
266-
break;
267-
}
268-
269-
const ObjCInterfaceDecl *ID =
270-
dyn_cast<ObjCInterfaceDecl>(FD->getDeclContext());
271-
const RecordDecl *RD = dyn_cast<RecordDecl>(FD->getDeclContext());
272-
if (RD) {
273-
if (RD->isUnion())
274-
return false;
275-
if (const CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(RD)) {
276-
if (!CRD->isStandardLayout())
277-
return false;
278-
}
279-
} else if (!ID)
280-
return false;
281-
282-
// See if this is the last field decl in the record.
283-
const Decl *D = FD;
284-
while ((D = D->getNextDeclInContext()))
285-
if (isa<FieldDecl>(D))
286-
return false;
287-
288-
return true;
289-
}
290-
291206
const ValueDecl *
292207
Expr::getAsBuiltinConstantDeclRef(const ASTContext &Context) const {
293208
Expr::EvalResult Eval;

clang/lib/AST/ExprConstant.cpp

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11592,16 +11592,9 @@ static bool isUserWritingOffTheEnd(const ASTContext &Ctx, const LValue &LVal) {
1159211592
// conservative with the last element in structs (if it's an array), so our
1159311593
// current behavior is more compatible than an explicit list approach would
1159411594
// be.
11595-
int StrictFlexArraysLevel = Ctx.getLangOpts().StrictFlexArrays;
1159611595
return LVal.InvalidBase &&
1159711596
Designator.Entries.size() == Designator.MostDerivedPathLength &&
1159811597
Designator.MostDerivedIsArrayElement &&
11599-
(Designator.isMostDerivedAnUnsizedArray() ||
11600-
(Designator.getMostDerivedArraySize() == 0 &&
11601-
StrictFlexArraysLevel < 3) ||
11602-
(Designator.getMostDerivedArraySize() == 1 &&
11603-
StrictFlexArraysLevel < 2) ||
11604-
StrictFlexArraysLevel == 0) &&
1160511598
isDesignatorAtObjectEnd(Ctx, LVal);
1160611599
}
1160711600

clang/lib/CodeGen/CGExpr.cpp

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -875,6 +875,44 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
875875
}
876876
}
877877

878+
/// Determine whether this expression refers to a flexible array member in a
879+
/// struct. We disable array bounds checks for such members.
880+
static bool isFlexibleArrayMemberExpr(const Expr *E) {
881+
// For compatibility with existing code, we treat arrays of length 0 or
882+
// 1 as flexible array members.
883+
// FIXME: This is inconsistent with the warning code in SemaChecking. Unify
884+
// the two mechanisms.
885+
const ArrayType *AT = E->getType()->castAsArrayTypeUnsafe();
886+
if (const auto *CAT = dyn_cast<ConstantArrayType>(AT)) {
887+
// FIXME: Sema doesn't treat [1] as a flexible array member if the bound
888+
// was produced by macro expansion.
889+
if (CAT->getSize().ugt(1))
890+
return false;
891+
} else if (!isa<IncompleteArrayType>(AT))
892+
return false;
893+
894+
E = E->IgnoreParens();
895+
896+
// A flexible array member must be the last member in the class.
897+
if (const auto *ME = dyn_cast<MemberExpr>(E)) {
898+
// FIXME: If the base type of the member expr is not FD->getParent(),
899+
// this should not be treated as a flexible array member access.
900+
if (const auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl())) {
901+
// FIXME: Sema doesn't treat a T[1] union member as a flexible array
902+
// member, only a T[0] or T[] member gets that treatment.
903+
if (FD->getParent()->isUnion())
904+
return true;
905+
RecordDecl::field_iterator FI(
906+
DeclContext::decl_iterator(const_cast<FieldDecl *>(FD)));
907+
return ++FI == FD->getParent()->field_end();
908+
}
909+
} else if (const auto *IRE = dyn_cast<ObjCIvarRefExpr>(E)) {
910+
return IRE->getDecl()->getNextIvar() == nullptr;
911+
}
912+
913+
return false;
914+
}
915+
878916
llvm::Value *CodeGenFunction::LoadPassedObjectSize(const Expr *E,
879917
QualType EltTy) {
880918
ASTContext &C = getContext();
@@ -916,11 +954,8 @@ llvm::Value *CodeGenFunction::LoadPassedObjectSize(const Expr *E,
916954

917955
/// If Base is known to point to the start of an array, return the length of
918956
/// that array. Return 0 if the length cannot be determined.
919-
static llvm::Value *getArrayIndexingBound(CodeGenFunction &CGF,
920-
const Expr *Base,
921-
QualType &IndexedType,
922-
ASTContext &Context,
923-
int StrictFlexArraysLevel) {
957+
static llvm::Value *getArrayIndexingBound(
958+
CodeGenFunction &CGF, const Expr *Base, QualType &IndexedType) {
924959
// For the vector indexing extension, the bound is the number of elements.
925960
if (const VectorType *VT = Base->getType()->getAs<VectorType>()) {
926961
IndexedType = Base->getType();
@@ -931,8 +966,7 @@ static llvm::Value *getArrayIndexingBound(CodeGenFunction &CGF,
931966

932967
if (const auto *CE = dyn_cast<CastExpr>(Base)) {
933968
if (CE->getCastKind() == CK_ArrayToPointerDecay &&
934-
!CE->getSubExpr()->IgnoreParens()->isFlexibleArrayMember(
935-
Context, std::max(StrictFlexArraysLevel, 1))) {
969+
!isFlexibleArrayMemberExpr(CE->getSubExpr())) {
936970
IndexedType = CE->getSubExpr()->getType();
937971
const ArrayType *AT = IndexedType->castAsArrayTypeUnsafe();
938972
if (const auto *CAT = dyn_cast<ConstantArrayType>(AT))
@@ -960,8 +994,7 @@ void CodeGenFunction::EmitBoundsCheck(const Expr *E, const Expr *Base,
960994
SanitizerScope SanScope(this);
961995

962996
QualType IndexedType;
963-
llvm::Value *Bound = getArrayIndexingBound(
964-
*this, Base, IndexedType, getContext(), getLangOpts().StrictFlexArrays);
997+
llvm::Value *Bound = getArrayIndexingBound(*this, Base, IndexedType);
965998
if (!Bound)
966999
return;
9671000

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6221,8 +6221,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
62216221
Args.AddLastArg(CmdArgs, options::OPT_funroll_loops,
62226222
options::OPT_fno_unroll_loops);
62236223

6224-
Args.AddLastArg(CmdArgs, options::OPT_fstrict_flex_arrays_EQ);
6225-
62266224
Args.AddLastArg(CmdArgs, options::OPT_pthread);
62276225

62286226
if (Args.hasFlag(options::OPT_mspeculative_load_hardening,

clang/lib/Sema/SemaChecking.cpp

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15716,6 +15716,53 @@ void Sema::CheckCastAlign(Expr *Op, QualType T, SourceRange TRange) {
1571615716
<< TRange << Op->getSourceRange();
1571715717
}
1571815718

15719+
/// Check whether this array fits the idiom of a size-one tail padded
15720+
/// array member of a struct.
15721+
///
15722+
/// We avoid emitting out-of-bounds access warnings for such arrays as they are
15723+
/// commonly used to emulate flexible arrays in C89 code.
15724+
static bool IsTailPaddedMemberArray(Sema &S, const llvm::APInt &Size,
15725+
const NamedDecl *ND) {
15726+
if (Size != 1 || !ND) return false;
15727+
15728+
const FieldDecl *FD = dyn_cast<FieldDecl>(ND);
15729+
if (!FD) return false;
15730+
15731+
// Don't consider sizes resulting from macro expansions or template argument
15732+
// substitution to form C89 tail-padded arrays.
15733+
15734+
TypeSourceInfo *TInfo = FD->getTypeSourceInfo();
15735+
while (TInfo) {
15736+
TypeLoc TL = TInfo->getTypeLoc();
15737+
// Look through typedefs.
15738+
if (TypedefTypeLoc TTL = TL.getAs<TypedefTypeLoc>()) {
15739+
const TypedefNameDecl *TDL = TTL.getTypedefNameDecl();
15740+
TInfo = TDL->getTypeSourceInfo();
15741+
continue;
15742+
}
15743+
if (ConstantArrayTypeLoc CTL = TL.getAs<ConstantArrayTypeLoc>()) {
15744+
const Expr *SizeExpr = dyn_cast<IntegerLiteral>(CTL.getSizeExpr());
15745+
if (!SizeExpr || SizeExpr->getExprLoc().isMacroID())
15746+
return false;
15747+
}
15748+
break;
15749+
}
15750+
15751+
const RecordDecl *RD = dyn_cast<RecordDecl>(FD->getDeclContext());
15752+
if (!RD) return false;
15753+
if (RD->isUnion()) return false;
15754+
if (const CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(RD)) {
15755+
if (!CRD->isStandardLayout()) return false;
15756+
}
15757+
15758+
// See if this is the last field decl in the record.
15759+
const Decl *D = FD;
15760+
while ((D = D->getNextDeclInContext()))
15761+
if (isa<FieldDecl>(D))
15762+
return false;
15763+
return true;
15764+
}
15765+
1571915766
void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
1572015767
const ArraySubscriptExpr *ASE,
1572115768
bool AllowOnePastEnd, bool IndexNegated) {
@@ -15868,9 +15915,10 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
1586815915
if (AllowOnePastEnd ? index.ule(size) : index.ult(size))
1586915916
return;
1587015917

15871-
// Also don't warn for flexible array members.
15872-
if (BaseExpr->isFlexibleArrayMember(Context,
15873-
getLangOpts().StrictFlexArrays))
15918+
// Also don't warn for arrays of size 1 which are members of some
15919+
// structure. These are often used to approximate flexible arrays in C89
15920+
// code.
15921+
if (IsTailPaddedMemberArray(*this, size, ND))
1587415922
return;
1587515923

1587615924
// Suppress the warning if the subscript expression (as identified by the

clang/lib/StaticAnalyzer/Core/MemRegion.cpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -789,9 +789,6 @@ DefinedOrUnknownSVal MemRegionManager::getStaticSize(const MemRegion *MR,
789789
if (isa<IncompleteArrayType>(AT))
790790
return true;
791791

792-
if (getContext().getLangOpts().StrictFlexArrays)
793-
return false;
794-
795792
if (const auto *CAT = dyn_cast<ConstantArrayType>(AT)) {
796793
const llvm::APInt &Size = CAT->getSize();
797794
if (Size.isZero())

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

Lines changed: 0 additions & 42 deletions
This file was deleted.

0 commit comments

Comments
 (0)