summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/lib/AST/ExprConstant.cpp17
-rw-r--r--clang/test/CodeGen/object-size.c25
-rw-r--r--clang/test/CodeGen/pass-object-size.c9
3 files changed, 40 insertions, 11 deletions
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 107913ed61b..15b554bf27a 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -6826,14 +6826,21 @@ static bool tryEvaluateBuiltinObjectSize(const Expr *E, unsigned Type,
// struct Foo *F = (struct Foo *)malloc(sizeof(struct Foo) + strlen(Bar));
// strcpy(&F->c[0], Bar);
//
- // So, if we see that we're examining a 1-length (or 0-length) array at the
- // end of a struct with an unknown base, we give up instead of breaking code
- // that behaves this way. Note that we only do this when Type=1, because
- // Type=3 is a lower bound, so answering conservatively is fine.
+ // So, if we see that we're examining an array at the end of a struct with an
+ // unknown base, we give up instead of breaking code that behaves this way.
+ // Note that we only do this when Type=1, because Type=3 is a lower bound, so
+ // answering conservatively is fine.
+ //
+ // We used to be a bit more aggressive here; we'd only be conservative if the
+ // array at the end was flexible, or if it had 0 or 1 elements. This broke
+ // some common standard library extensions (PR30346), but was otherwise
+ // seemingly fine. It may be useful to reintroduce this behavior with some
+ // sort of whitelist. OTOH, it seems that GCC is always conservative with the
+ // last element in structs (if it's an array), so our current behavior is more
+ // compatible than a whitelisting approach would be.
if (End.InvalidBase && SubobjectOnly && Type == 1 &&
End.Designator.Entries.size() == End.Designator.MostDerivedPathLength &&
End.Designator.MostDerivedIsArrayElement &&
- End.Designator.MostDerivedArraySize < 2 &&
isDesignatorAtObjectEnd(Info.Ctx, End))
return false;
diff --git a/clang/test/CodeGen/object-size.c b/clang/test/CodeGen/object-size.c
index 6aee57375a4..a3f3bce9295 100644
--- a/clang/test/CodeGen/object-size.c
+++ b/clang/test/CodeGen/object-size.c
@@ -276,7 +276,7 @@ void test23(struct Test23Ty *p) {
// CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
gi = __builtin_object_size(&p->t[5], 0);
- // CHECK: store i32 20
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
gi = __builtin_object_size(&p->t[5], 1);
// CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 true)
gi = __builtin_object_size(&p->t[5], 2);
@@ -444,7 +444,7 @@ void test29(struct DynStructVar *dv, struct DynStruct0 *d0,
// CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
gi = __builtin_object_size(ss->snd, 0);
- // CHECK: store i32 2
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
gi = __builtin_object_size(ss->snd, 1);
// CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 true)
gi = __builtin_object_size(ss->snd, 2);
@@ -505,7 +505,7 @@ void test31() {
// CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
gi = __builtin_object_size(ds1[9].snd, 1);
- // CHECK: store i32 2
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
gi = __builtin_object_size(&ss[9].snd[0], 1);
// CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
@@ -517,3 +517,22 @@ void test31() {
// CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
gi = __builtin_object_size(&dsv[9].snd[0], 1);
}
+
+// CHECK-LABEL: @PR30346
+void PR30346() {
+ struct sa_family_t {};
+ struct sockaddr {
+ struct sa_family_t sa_family;
+ char sa_data[14];
+ };
+
+ struct sockaddr *sa;
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
+ gi = __builtin_object_size(sa->sa_data, 0);
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 false)
+ gi = __builtin_object_size(sa->sa_data, 1);
+ // CHECK: call i64 @llvm.objectsize.i64.p0i8(i8* %{{.*}}, i1 true)
+ gi = __builtin_object_size(sa->sa_data, 2);
+ // CHECK: store i32 14
+ gi = __builtin_object_size(sa->sa_data, 3);
+}
diff --git a/clang/test/CodeGen/pass-object-size.c b/clang/test/CodeGen/pass-object-size.c
index 6e2bc2090ed..6f5827befa7 100644
--- a/clang/test/CodeGen/pass-object-size.c
+++ b/clang/test/CodeGen/pass-object-size.c
@@ -59,7 +59,8 @@ void test1() {
// CHECK-LABEL: define void @test2
void test2(struct Foo *t) {
- // CHECK: call i32 @ObjectSize1(i8* %{{.*}}, i64 36)
+ // CHECK: [[VAR:%[0-9]+]] = call i64 @llvm.objectsize
+ // CHECK: call i32 @ObjectSize1(i8* %{{.*}}, i64 [[VAR]])
gi = ObjectSize1(&t->t[1]);
// CHECK: call i32 @ObjectSize3(i8* %{{.*}}, i64 36)
gi = ObjectSize3(&t->t[1]);
@@ -168,7 +169,8 @@ void test4(struct Foo *t) {
// CHECK: call i32 @_Z27NoViableOverloadObjectSize0PvU17pass_object_size0(i8* %{{.*}}, i64 %{{.*}})
gi = NoViableOverloadObjectSize0(&t[1].t[1]);
- // CHECK: call i32 @_Z27NoViableOverloadObjectSize1PvU17pass_object_size1(i8* %{{.*}}, i64 36)
+ // CHECK: [[VAR:%[0-9]+]] = call i64 @llvm.objectsize
+ // CHECK: call i32 @_Z27NoViableOverloadObjectSize1PvU17pass_object_size1(i8* %{{.*}}, i64 [[VAR]])
gi = NoViableOverloadObjectSize1(&t[1].t[1]);
// CHECK: call i32 @_Z27NoViableOverloadObjectSize2PvU17pass_object_size2(i8* %{{.*}}, i64 %{{.*}})
gi = NoViableOverloadObjectSize2(&t[1].t[1]);
@@ -274,7 +276,8 @@ void test7() {
// CHECK-LABEL: define void @test8
void test8(struct Foo *t) {
- // CHECK: call i32 @"\01Identity"(i8* %{{.*}}, i64 36)
+ // CHECK: [[VAR:%[0-9]+]] = call i64 @llvm.objectsize
+ // CHECK: call i32 @"\01Identity"(i8* %{{.*}}, i64 [[VAR]])
gi = AsmObjectSize1(&t[1].t[1]);
// CHECK: call i32 @"\01Identity"(i8* %{{.*}}, i64 36)
gi = AsmObjectSize3(&t[1].t[1]);
OpenPOWER on IntegriCloud