summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGeorge Burgess IV <george.burgess.iv@gmail.com>2015-09-04 22:36:18 +0000
committerGeorge Burgess IV <george.burgess.iv@gmail.com>2015-09-04 22:36:18 +0000
commit7a7e52f3db9e806149a36fe3469a36a2e1bfe1f2 (patch)
tree71cae11746ff2b04e04ebc06c72bae4d45219feb
parent8392772a6874cff944e5d86fc7710793795d3eb7 (diff)
Fix a bug in __builtin_object_size cast removal
Apparently there are many cast kinds that may cause implicit pointer arithmetic to happen. In light of this, the cast ignoring logic introduced in r246877 has been changed to only ignore a small set of cast kinds, and a test for this behavior has been added. Thanks to Richard for catching this before it became a bug report. :) git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@246890 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/AST/ExprConstant.cpp13
-rw-r--r--test/CodeGen/object-size.cpp30
2 files changed, 40 insertions, 3 deletions
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index dea85d84a2..5eaf40eb2a 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -6249,8 +6249,8 @@ static QualType getObjectType(APValue::LValueBase B) {
}
/// A more selective version of E->IgnoreParenCasts for
-/// TryEvaluateBuiltinObjectSize. This ignores casts/parens that serve only to
-/// change the type of E.
+/// TryEvaluateBuiltinObjectSize. This ignores some casts/parens that serve only
+/// to change the type of E.
/// Ex. For E = `(short*)((char*)(&foo))`, returns `&foo`
///
/// Always returns an RValue with a pointer representation.
@@ -6259,7 +6259,14 @@ static const Expr *ignorePointerCastsAndParens(const Expr *E) {
auto *NoParens = E->IgnoreParens();
auto *Cast = dyn_cast<CastExpr>(NoParens);
- if (Cast == nullptr || Cast->getCastKind() == CK_DerivedToBase)
+ if (Cast == nullptr)
+ return NoParens;
+
+ // We only conservatively allow a few kinds of casts, because this code is
+ // inherently a simple solution that seeks to support the common case.
+ auto CastKind = Cast->getCastKind();
+ if (CastKind != CK_NoOp && CastKind != CK_BitCast &&
+ CastKind != CK_AddressSpaceConversion)
return NoParens;
auto *SubExpr = Cast->getSubExpr();
diff --git a/test/CodeGen/object-size.cpp b/test/CodeGen/object-size.cpp
new file mode 100644
index 0000000000..1c9d1ae945
--- /dev/null
+++ b/test/CodeGen/object-size.cpp
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s | FileCheck %s
+
+// C++-specific tests for __builtin_object_size
+
+int gi;
+
+// CHECK-LABEL: define void @_Z5test1v()
+void test1() {
+ // Guaranteeing that our cast removal logic doesn't break more interesting
+ // cases.
+ struct A { int a; };
+ struct B { int b; };
+ struct C: public A, public B {};
+
+ C c;
+
+ // CHECK: store i32 8
+ gi = __builtin_object_size(&c, 0);
+ // CHECK: store i32 8
+ gi = __builtin_object_size((A*)&c, 0);
+ // CHECK: store i32 4
+ gi = __builtin_object_size((B*)&c, 0);
+
+ // CHECK: store i32 8
+ gi = __builtin_object_size((char*)&c, 0);
+ // CHECK: store i32 8
+ gi = __builtin_object_size((char*)(A*)&c, 0);
+ // CHECK: store i32 4
+ gi = __builtin_object_size((char*)(B*)&c, 0);
+}