Skip to content

Commit df368fd

Browse files
bcardosolopeslanza
authored andcommitted
[CIR][Lifetime] Add support for checkCopyAssignment and fix bug in state comparison
1 parent 9d4b8a9 commit df368fd

File tree

2 files changed

+51
-19
lines changed

2 files changed

+51
-19
lines changed

clang/lib/CIR/Dialect/Transforms/LifetimeCheck.cpp

Lines changed: 39 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ struct LifetimeCheckPass : public LifetimeCheckBase<LifetimeCheckPass> {
4545

4646
void checkCtor(CallOp callOp, const clang::CXXConstructorDecl *ctor);
4747
void checkMoveAssignment(CallOp callOp, const clang::CXXMethodDecl *m);
48+
void checkCopyAssignment(CallOp callOp, const clang::CXXMethodDecl *m);
49+
void checkNonConstUseOfOwner(CallOp callOp);
4850
void checkOperatorStar(CallOp callOp);
4951

5052
// Tracks current module.
@@ -141,14 +143,14 @@ struct LifetimeCheckPass : public LifetimeCheckBase<LifetimeCheckPass> {
141143
bool operator<(const State &RHS) const {
142144
// FIXME: note that this makes the ordering non-deterministic, do
143145
// we really care?
144-
if (val.getInt() == LocalValue && RHS.val.getInt() == LocalValue)
146+
if (hasValue() && RHS.hasValue())
145147
return val.getPointer().getAsOpaquePointer() <
146148
RHS.val.getPointer().getAsOpaquePointer();
147149
else
148150
return val.getInt() < RHS.val.getInt();
149151
}
150152
bool operator==(const State &RHS) const {
151-
if (val.getInt() == LocalValue && RHS.val.getInt() == LocalValue)
153+
if (hasValue() && RHS.hasValue())
152154
return val.getPointer() == RHS.val.getPointer();
153155
else
154156
return val.getInt() == RHS.val.getInt();
@@ -970,6 +972,7 @@ void LifetimeCheckPass::checkMoveAssignment(CallOp callOp,
970972
auto src = callOp.getOperand(1);
971973

972974
// Currently only handle move assignments between pointer categories.
975+
// TODO: add Owner category
973976
if (!(ptrs.count(dst) && ptrs.count(src)))
974977
return;
975978

@@ -984,6 +987,20 @@ void LifetimeCheckPass::checkMoveAssignment(CallOp callOp,
984987
getPmap()[src].insert(State::getInvalid());
985988
}
986989

990+
void LifetimeCheckPass::checkCopyAssignment(CallOp callOp,
991+
const clang::CXXMethodDecl *m) {
992+
// MyIntOwner::operator=(MyIntOwner&)(%dst, %src)
993+
auto dst = callOp.getOperand(0);
994+
auto src = callOp.getOperand(1);
995+
996+
// Currently only handle copy assignments between owner categories.
997+
// TODO: add Ptr category
998+
if (!(owners.count(dst) && owners.count(src)))
999+
return;
1000+
1001+
checkNonConstUseOfOwner(callOp);
1002+
}
1003+
9871004
// User defined ctors that initialize from owner types is one
9881005
// way of tracking owned pointers.
9891006
//
@@ -1085,6 +1102,23 @@ bool LifetimeCheckPass::isNonConstUseOfOwner(CallOp callOp,
10851102
return false;
10861103
}
10871104

1105+
void LifetimeCheckPass::checkNonConstUseOfOwner(CallOp callOp) {
1106+
auto ownerAddr = callOp.getOperand(0);
1107+
// 2.4.2 - On every non-const use of a local Owner o:
1108+
//
1109+
// - For each entry e in pset(s): Remove e from pset(s), and if no other
1110+
// Owner’s pset contains only e, then KILL(e).
1111+
kill(State::getOwnedBy(ownerAddr), InvalidStyle::NonConstUseOfOwner,
1112+
callOp.getLoc());
1113+
1114+
// - Set pset(o) = {o__N'}, where N is one higher than the highest
1115+
// previously used suffix. For example, initially pset(o) is {o__1'}, on
1116+
// o’s first non-const use pset(o) becomes {o__2'}, on o’s second non-const
1117+
// use pset(o) becomes {o__3'}, and so on.
1118+
incOwner(ownerAddr);
1119+
return;
1120+
}
1121+
10881122
void LifetimeCheckPass::checkCall(CallOp callOp) {
10891123
if (callOp.getNumOperands() == 0)
10901124
return;
@@ -1098,7 +1132,7 @@ void LifetimeCheckPass::checkCall(CallOp callOp) {
10981132
if (methodDecl->isMoveAssignmentOperator())
10991133
return checkMoveAssignment(callOp, methodDecl);
11001134
if (methodDecl->isCopyAssignmentOperator())
1101-
llvm_unreachable("NYI");
1135+
return checkCopyAssignment(callOp, methodDecl);
11021136
if (isOperatorStar(methodDecl))
11031137
return checkOperatorStar(callOp);
11041138
if (sinkUnsupportedOperator(methodDecl))
@@ -1107,22 +1141,8 @@ void LifetimeCheckPass::checkCall(CallOp callOp) {
11071141
// For any other methods...
11081142

11091143
// Non-const member call to a Owner invalidates any of its users.
1110-
if (isNonConstUseOfOwner(callOp, methodDecl)) {
1111-
auto ownerAddr = callOp.getOperand(0);
1112-
// 2.4.2 - On every non-const use of a local Owner o:
1113-
//
1114-
// - For each entry e in pset(s): Remove e from pset(s), and if no other
1115-
// Owner’s pset contains only e, then KILL(e).
1116-
kill(State::getOwnedBy(ownerAddr), InvalidStyle::NonConstUseOfOwner,
1117-
callOp.getLoc());
1118-
1119-
// - Set pset(o) = {o__N'}, where N is one higher than the highest
1120-
// previously used suffix. For example, initially pset(o) is {o__1'}, on
1121-
// o’s first non-const use pset(o) becomes {o__2'}, on o’s second non-const
1122-
// use pset(o) becomes {o__3'}, and so on.
1123-
incOwner(ownerAddr);
1124-
return;
1125-
}
1144+
if (isNonConstUseOfOwner(callOp, methodDecl))
1145+
return checkNonConstUseOfOwner(callOp);
11261146

11271147
// Take a pset(Ptr) = { Ownr' } where Own got invalidated, this will become
11281148
// invalid access to Ptr if any of its methods are used.

clang/test/CIR/Transforms/lifetime-check-owner.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,16 @@ void yolo3() {
5656
// expected-remark@-1 {{pset => { invalid }}}
5757
(void)q.read(); // expected-warning {{use of invalid pointer 'q'}}
5858
// expected-remark@-1 {{pset => { invalid }}}
59+
}
60+
61+
void yolo4() {
62+
MyIntOwner o0(1);
63+
MyIntOwner o1(2);
64+
MyIntPointer p{o0}, q{o1};
65+
p.read(); // expected-remark {{pset => { o0__1' }}}
66+
q.read(); // expected-remark {{pset => { o1__1' }}}
67+
o0 = o1; // expected-note {{invalidated by non-const use of owner type}}
68+
p.read(); // expected-warning {{use of invalid pointer 'p'}}
69+
// expected-remark@-1 {{pset => { invalid }}}
70+
q.read(); // expected-remark {{pset => { o1__1' }}}
5971
}

0 commit comments

Comments
 (0)