Skip to content

Commit 01b9e61

Browse files
committed
[Clang][Codegen] Truncate initializers of union bitfield members
If an initial value is given for a bitfield that does not fit in the bitfield, the value should be truncated. Constant folding for expressions did not account for this truncation in the case of union member functions, despite a warning being emitted. In some contexts, evaluation of expressions was not enabled unless C++11, ROPI or RWPI was enabled. Differential Revision: https://reviews.llvm.org/D93101
1 parent fc4e8a3 commit 01b9e61

File tree

2 files changed

+74
-1
lines changed

2 files changed

+74
-1
lines changed

clang/lib/AST/ExprConstant.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9798,7 +9798,14 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
97989798
ThisOverrideRAII ThisOverride(*Info.CurrentCall, &This,
97999799
isa<CXXDefaultInitExpr>(InitExpr));
98009800

9801-
return EvaluateInPlace(Result.getUnionValue(), Info, Subobject, InitExpr);
9801+
if (EvaluateInPlace(Result.getUnionValue(), Info, Subobject, InitExpr)) {
9802+
if (Field->isBitField())
9803+
return truncateBitfieldValue(Info, InitExpr, Result.getUnionValue(),
9804+
Field);
9805+
return true;
9806+
}
9807+
9808+
return false;
98029809
}
98039810

98049811
if (!Result.hasValue())

clang/test/CodeGenCXX/bitfield-layout.cpp

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// RUN: %clang_cc1 %s -triple=i386-apple-darwin10 -emit-llvm -o - -O3 | FileCheck %s
33
// RUN: %clang_cc1 %s -triple=aarch64_be-none-eabi -emit-llvm -o - -O3 | FileCheck %s
44
// RUN: %clang_cc1 %s -triple=thumbv7_be-none-eabi -emit-llvm -o - -O3 | FileCheck %s
5+
// RUN: %clang_cc1 %s -triple=x86_64-unknown-unknown -emit-llvm -o - -O3 -std=c++11 | FileCheck -check-prefix=CHECK -check-prefix=CHECK-LP64 %s
56

67
// CHECK-LP64: %union.Test1 = type { i32, [4 x i8] }
78
union Test1 {
@@ -84,3 +85,68 @@ int test_init() {
8485
// CHECK: ret i32 0
8586
return 0;
8687
}
88+
89+
extern "C" {
90+
int test_trunc_int() {
91+
union {
92+
int i : 4; // truncated to 0b1111 == -1
93+
} const U = {15}; // 0b00001111
94+
return U.i;
95+
}
96+
// CHECK: define dso_local i32 @test_trunc_int()
97+
// CHECK: ret i32 -1
98+
99+
int test_trunc_three_bits() {
100+
union {
101+
int i : 3; // truncated to 0b111 == -1
102+
} const U = {15}; // 0b00001111
103+
return U.i;
104+
}
105+
// CHECK: define dso_local i32 @test_trunc_three_bits()
106+
// CHECK: ret i32 -1
107+
108+
int test_trunc_1() {
109+
union {
110+
int i : 1; // truncated to 0b1 == -1
111+
} const U = {15}; // 0b00001111
112+
return U.i;
113+
}
114+
// CHECK: define dso_local i32 @test_trunc_1()
115+
// CHECK: ret i32 -1
116+
117+
int test_trunc_zero() {
118+
union {
119+
int i : 4; // truncated to 0b0000 == 0
120+
} const U = {80}; // 0b01010000
121+
return U.i;
122+
}
123+
// CHECK: define dso_local i32 @test_trunc_zero()
124+
// CHECK: ret i32 0
125+
126+
int test_constexpr() {
127+
union {
128+
int i : 3; // truncated to 0b111 == -1
129+
} const U = {1 + 2 + 4 + 8}; // 0b00001111
130+
return U.i;
131+
}
132+
// CHECK: define dso_local i32 @test_constexpr()
133+
// CHECK: ret i32 -1
134+
135+
int test_notrunc() {
136+
union {
137+
int i : 12; // not truncated
138+
} const U = {1 + 2 + 4 + 8}; // 0b00001111
139+
return U.i;
140+
}
141+
// CHECK: define dso_local i32 @test_notrunc()
142+
// CHECK: ret i32 15
143+
144+
long long test_trunc_long_long() {
145+
union {
146+
long long i : 14; // truncated to 0b00111101001101 ==
147+
} const U = {0b0100111101001101};
148+
return U.i;
149+
}
150+
// CHECK: define dso_local i64 @test_trunc_long_long()
151+
// CHECK: ret i64 3917
152+
}

0 commit comments

Comments
 (0)