Skip to content

Commit cb45aba

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

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
@@ -44,6 +44,8 @@ struct LifetimeCheckPass : public LifetimeCheckBase<LifetimeCheckPass> {
4444

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

4951
// Tracks current module.
@@ -140,13 +142,13 @@ struct LifetimeCheckPass : public LifetimeCheckBase<LifetimeCheckPass> {
140142
bool operator<(const State &RHS) const {
141143
// FIXME: note that this makes the ordering non-deterministic, do
142144
// we really care?
143-
if (val.getInt() == LocalValue && RHS.val.getInt() == LocalValue)
145+
if (hasValue() && RHS.hasValue())
144146
return val.getPointer().getAsOpaquePointer() <
145147
RHS.val.getPointer().getAsOpaquePointer();
146148
return val.getInt() < RHS.val.getInt();
147149
}
148150
bool operator==(const State &RHS) const {
149-
if (val.getInt() == LocalValue && RHS.val.getInt() == LocalValue)
151+
if (hasValue() && RHS.hasValue())
150152
return val.getPointer() == RHS.val.getPointer();
151153
return val.getInt() == RHS.val.getInt();
152154
}
@@ -968,6 +970,7 @@ void LifetimeCheckPass::checkMoveAssignment(CallOp callOp,
968970
auto src = callOp.getOperand(1);
969971

970972
// Currently only handle move assignments between pointer categories.
973+
// TODO: add Owner category
971974
if (!(ptrs.count(dst) && ptrs.count(src)))
972975
return;
973976

@@ -982,6 +985,20 @@ void LifetimeCheckPass::checkMoveAssignment(CallOp callOp,
982985
getPmap()[src].insert(State::getInvalid());
983986
}
984987

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

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

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

11251145
// Take a pset(Ptr) = { Ownr' } where Own got invalidated, this will become
11261146
// 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)