<< TRange << Op->getSourceRange();
}
+/// \brief Check whether this array fits the idiom of a size-one tail padded
+/// array member of a struct.
+///
+/// We avoid emitting out-of-bounds access warnings for such arrays as they are
+/// commonly used to emulate flexible arrays in C89 code.
+static bool IsTailPaddedMemberArray(Sema &S, llvm::APInt Size,
+ const NamedDecl *ND) {
+ if (Size != 1 || !ND) return false;
+
+ const FieldDecl *FD = dyn_cast<FieldDecl>(ND);
+ if (!FD) return false;
+
+ // Don't consider sizes resulting from macro expansions or template argument
+ // substitution to form C89 tail-padded arrays.
+ ConstantArrayTypeLoc TL =
+ cast<ConstantArrayTypeLoc>(FD->getTypeSourceInfo()->getTypeLoc());
+ const Expr *SizeExpr = dyn_cast<IntegerLiteral>(TL.getSizeExpr());
+ if (!SizeExpr || SizeExpr->getExprLoc().isMacroID())
+ return false;
+
+ const RecordDecl *RD = dyn_cast<RecordDecl>(FD->getDeclContext());
+ if (!RD || !RD->isStruct())
+ return false;
+
+ // This is annoyingly inefficient. We don't have a bi-directional iterator
+ // here so we can't walk backwards through the decls, we have to walk
+ // forward.
+ for (RecordDecl::field_iterator FI = RD->field_begin(),
+ FEnd = RD->field_end();
+ FI != FEnd; ++FI) {
+ if (*FI == FD)
+ return ++FI == FEnd;
+ }
+ return false;
+}
+
static void CheckArrayAccess_Check(Sema &S,
const clang::ArraySubscriptExpr *E) {
const Expr *BaseExpr = E->getBase()->IgnoreParenImpCasts();
return;
const NamedDecl *ND = NULL;
- bool IsMemberDecl = false;
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(BaseExpr))
ND = dyn_cast<NamedDecl>(DRE->getDecl());
- if (const MemberExpr *ME = dyn_cast<MemberExpr>(BaseExpr)) {
+ if (const MemberExpr *ME = dyn_cast<MemberExpr>(BaseExpr))
ND = dyn_cast<NamedDecl>(ME->getMemberDecl());
- IsMemberDecl = true;
- }
if (index.isUnsigned() || !index.isNegative()) {
llvm::APInt size = ArrayTy->getSize();
// Also don't warn for arrays of size 1 which are members of some
// structure. These are often used to approximate flexible arrays in C89
// code.
- // FIXME: We should also check whether there are any members after this
- // member within the struct as that precludes the usage as a flexible
- // array. We should also potentially check for an explicit '1' as opposed
- // to a macro or template argument which might accidentally and erroneously
- // expand to '1'.
- if (IsMemberDecl && size == 1)
+ if (IsTailPaddedMemberArray(S, size, ND))
return;
S.DiagRuntimeBehavior(E->getBase()->getLocStart(), BaseExpr,
S.PDiag(diag::warn_array_index_exceeds_bounds)
<< index.toString(10, true)
<< size.toString(10, true)
+ << (unsigned)size.ugt(1)
<< IndexExpr->getSourceRange());
} else {
S.DiagRuntimeBehavior(E->getBase()->getLocStart(), BaseExpr,
int foo() {
int x[2]; // expected-note 4 {{array 'x' declared here}}
int y[2]; // expected-note 2 {{array 'y' declared here}}
+ int z[1]; // expected-note {{array 'z' declared here}}
int *p = &y[2]; // no-warning
(void) sizeof(x[2]); // no-warning
y[2] = 2; // expected-warning {{array index of '2' indexes past the end of an array (that contains 2 elements)}}
+ z[1] = 'x'; // expected-warning {{array index of '1' indexes past the end of an array (that contains 1 element)}}
return x[2] + // expected-warning {{array index of '2' indexes past the end of an array (that contains 2 elements)}}
y[-1] + // expected-warning {{array index of '-1' indexes before the beginning of the array}}
x[sizeof(x)] + // expected-warning {{array index of '8' indexes past the end of an array (that contains 2 elements)}}
namespace tailpad {
struct foo {
+ char c1[1]; // expected-note {{declared here}}
int x;
- char c[1];
+ char c2[1];
};
char bar(struct foo *F) {
- return F->c[3]; // no warning, foo could have tail padding allocated.
+ return F->c1[3]; // expected-warning {{array index of '3' indexes past the end of an array (that contains 1 element)}}
+ return F->c2[3]; // no warning, foo could have tail padding allocated.
+ }
+}
+
+namespace metaprogramming {
+#define ONE 1
+ struct foo { char c[ONE]; }; // expected-note {{declared here}}
+ template <int N> struct bar { char c[N]; }; // expected-note {{declared here}}
+
+ char test(foo *F, bar<1> *B) {
+ return F->c[3] + // expected-warning {{array index of '3' indexes past the end of an array (that contains 1 element)}}
+ B->c[3]; // expected-warning {{array index of '3' indexes past the end of an array (that contains 1 element)}}
}
}