Skip to content

Commit 3de2824

Browse files
authored
[CIR] Added support for CK_BaseToDerived in emitCastLValue (#1864)
Fixes #1808
1 parent 9e61bea commit 3de2824

File tree

2 files changed

+108
-1
lines changed

2 files changed

+108
-1
lines changed

clang/lib/CIR/CodeGen/CIRGenExpr.cpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2016,7 +2016,25 @@ LValue CIRGenFunction::emitCastLValue(const CastExpr *E) {
20162016
case CK_ToUnion:
20172017
assert(0 && "NYI");
20182018
case CK_BaseToDerived: {
2019-
assert(0 && "NYI");
2019+
const auto *derivedClassTy = E->getType()->castAs<RecordType>();
2020+
auto *derivedClassDecl = cast<CXXRecordDecl>(derivedClassTy->getDecl());
2021+
2022+
LValue lv = emitLValue(E->getSubExpr());
2023+
2024+
// Perform the base-to-derived conversion
2025+
Address derived = getAddressOfDerivedClass(
2026+
lv.getAddress(), derivedClassDecl, E->path_begin(), E->path_end(),
2027+
/*NullCheckValue=*/false);
2028+
// C++11 [expr.static.cast]p2: Behavior is undefined if a downcast is
2029+
// performed and the object is not of the derived type.
2030+
if (sanitizePerformTypeCheck())
2031+
llvm_unreachable("TCK_DowncastReference NYI");
2032+
2033+
if (SanOpts.has(SanitizerKind::CFIDerivedCast))
2034+
llvm_unreachable("CFITypeCheckKind NYI");
2035+
2036+
return makeAddrLValue(derived, E->getType(), lv.getBaseInfo(),
2037+
CGM.getTBAAInfoForSubobject(lv, E->getType()));
20202038
}
20212039
case CK_LValueBitCast: {
20222040
// This must be a reinterpret_cast (or c-style equivalent).
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o - 2>&1 | FileCheck %s --check-prefix=CIR
2+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o - 2>&1 | FileCheck %s --check-prefix=LLVM
3+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o - 2>&1 | FileCheck %s --check-prefix=OGCG
4+
class Base {
5+
// CIR-LABEL: _ZN4BaseaSERS_
6+
// CIR-SAME: ([[ARG0:%.*]]: !cir.ptr{{.*}}, [[ARG1:%.*]]: !cir.ptr{{.*}})
7+
// CIR: [[ALLOCA_0:%.*]] = cir.alloca
8+
// CIR: [[ALLOCA_1:%.*]] = cir.alloca
9+
// CIR: [[ALLOCA_2:%.*]] = cir.alloca
10+
// CIR: cir.store [[ARG0]], [[ALLOCA_0]]
11+
// CIR: cir.store [[ARG1]], [[ALLOCA_1]]
12+
// CIR: [[LD_0:%.*]] = cir.load deref [[ALLOCA_0]]
13+
// CIR: cir.store align(8) [[LD_0]], [[ALLOCA_2]]
14+
// CIR: [[LD_1:%.*]] = cir.load [[ALLOCA_2]]
15+
// CIR: cir.return [[LD_1]]
16+
17+
// LLVM-LABEL: _ZN4BaseaSERS_
18+
// LLVM-SAME: (ptr [[ARG0:%.*]], ptr [[ARG1:%.*]])
19+
// LLVM: [[TMP3:%.*]] = alloca ptr, i64 1, align 8
20+
// LLVM-NEXT: [[TMP4:%.*]] = alloca ptr, i64 1, align 8
21+
// LLVM-NEXT: [[TMP5:%.*]] = alloca ptr, i64 1, align 8
22+
// LLVM-NEXT: store ptr [[ARG0]], ptr [[TMP3]], align 8
23+
// LLVM-NEXT: store ptr [[ARG1]], ptr [[TMP4]], align 8
24+
// LLVM-NEXT: [[TMP6:%.*]] = load ptr, ptr [[TMP3]], align 8
25+
// LLVM-NEXT: store ptr [[TMP6]], ptr [[TMP5]], align 8
26+
// LLVM-NEXT: [[TMP7:%.*]] = load ptr, ptr [[TMP5]], align 8
27+
// LLVM-NEXT: ret ptr [[TMP7]]
28+
29+
public:
30+
Base &operator=(Base &b) {
31+
return *this;
32+
}
33+
};
34+
35+
class Derived : Base {
36+
Derived &operator=(Derived &);
37+
};
38+
Derived &Derived::operator=(Derived &B) {
39+
// CIR-LABEL: _ZN7DerivedaSERS_
40+
// CIR-SAME: [[ARG0:%.*]]: !cir.ptr{{.*}}, [[ARG1:%.*]]: !cir.ptr{{.*}}
41+
// CIR: cir.store [[ARG0]], [[ALLOCA_0:%.*]] :
42+
// CIR: cir.store [[ARG1]], [[ALLOCA_1:%.*]] :
43+
// CIR: [[LD_0:%.*]] = cir.load [[ALLOCA_0]]
44+
// CIR: [[BASE_ADDR_0:%.*]] = cir.base_class_addr [[LD_0]]
45+
// CIR: [[LD_1:%.*]] = cir.load [[ALLOCA_1]]
46+
// CIR: [[BASE_ADDR_1:%.*]] = cir.base_class_addr [[LD_1]]
47+
// CIR: [[CALL:%.*]] = cir.call @_ZN4BaseaSERS_
48+
// CIR: [[DERIVED_ADDR:%.*]] = cir.derived_class_addr [[CALL]]
49+
// CIR: cir.store align(8) [[DERIVED_ADDR]], [[ALLOCA_2:%.*]] :
50+
// CIR: [[LD_2:%.*]] = cir.load [[ALLOCA_2]]
51+
// CIR: cir.return [[LD_2]]
52+
53+
// LLVM-LABEL: _ZN7DerivedaSERS_
54+
// LLVM-SAME: (ptr [[ARG0:%.*]], ptr [[ARG1:%.*]])
55+
// LLVM: [[TMP3:%.*]] = alloca ptr, i64 1, align 8
56+
// LLVM-NEXT: [[TMP4:%.*]] = alloca ptr, i64 1, align 8
57+
// LLVM-NEXT: [[TMP5:%.*]] = alloca ptr, i64 1, align 8
58+
// LLVM-NEXT: store ptr [[ARG0]], ptr [[TMP3]], align 8
59+
// LLVM-NEXT: store ptr [[ARG1]], ptr [[TMP4]], align 8
60+
// LLVM-NEXT: [[TMP6:%.*]] = load ptr, ptr [[TMP3]], align 8
61+
// LLVM-NEXT: [[TMP7:%.*]] = load ptr, ptr [[TMP4]], align 8
62+
// LLVM-NEXT: [[TMP8:%.*]] = call ptr @_ZN4BaseaSERS_(ptr [[TMP6]], ptr [[TMP7]])
63+
// LLVM-NEXT: [[TMP9:%.*]] = getelementptr i8, ptr [[TMP8]], i32 0
64+
// LLVM-NEXT: store ptr [[TMP9]], ptr [[TMP5]], align 8
65+
// LLVM-NEXT: [[TMP10:%.*]] = load ptr, ptr [[TMP5]], align 8
66+
// LLVM-NEXT: ret ptr [[TMP10]]
67+
68+
// OGCG-LABEL: @_ZN7DerivedaSERS_
69+
// OGCG-SAME: (ptr{{.*}}[[ARG0:%.*]], ptr{{.*}}[[ARG1:%.*]])
70+
// OGCG: [[TMP3:%.*]] = alloca ptr, align 8
71+
// OGCG-NEXT: [[TMP4:%.*]] = alloca ptr, align 8
72+
// OGCG-NEXT: store ptr [[ARG0]], ptr [[TMP3]], align 8
73+
// OGCG-NEXT: store ptr [[ARG1]], ptr [[TMP4]], align 8
74+
// OGCG-NEXT: [[TMP5:%.*]] = load ptr, ptr [[TMP3]], align 8
75+
// OGCG-NEXT: [[TMP6:%.*]] = load ptr, ptr [[TMP4]], align 8
76+
// OGCG-NEXT: [[TMP7:%.*]] = call{{.*}}ptr @_ZN4BaseaSERS_(ptr{{.*}}[[TMP5]], ptr{{.*}}[[TMP6]])
77+
// OGCG-NEXT: ret ptr [[TMP7]]
78+
return (Derived &)Base::operator=(B);
79+
}
80+
81+
// OGCG-LABEL: define{{.*}}@_ZN4BaseaSERS_
82+
// OGCG-SAME: (ptr{{.*}}[[BASE_ARG0:%.*]], ptr{{.*}}[[BASE_ARG1:%.*]])
83+
// OGCG: [[TMP3:%.*]] = alloca ptr, align 8
84+
// OGCG-NEXT: [[TMP4:%.*]] = alloca ptr, align 8
85+
// OGCG-NEXT: store ptr [[BASE_ARG0]], ptr [[TMP3]], align 8
86+
// OGCG-NEXT: store ptr [[BASE_ARG1]], ptr [[TMP4]], align 8
87+
// OGCG-NEXT: [[TMP5:%.*]] = load ptr, ptr [[TMP3]], align 8
88+
// OGCG-NEXT: ret ptr [[TMP5]]
89+

0 commit comments

Comments
 (0)