Skip to content

Commit ccc4732

Browse files
dougsonosDoug WyattSirraide
authored
[Clang] FunctionEffects: properly extract the type of a bound member member function from a CallExpr. (llvm#166101)
There's a bug illustrated by this example: ``` template <typename T> struct Holder { T value; T& operator*() { return value; } }; struct X { using Dispatch = float (X::*)() [[clang::nonblocking]]; void fails(Holder<Dispatch>& holder) [[clang::nonblocking]] { (this->*(*holder))(); <<< the expression is incorrectly determined not to be nonblocking } void succeeds(Holder<Dispatch>& holder) [[clang::nonblocking]] { auto func = *holder; (this->*func)(); } }; ``` In both cases we have a `CXXMemberCallExpr`. In `succeeds`, the expression refers to a `Decl` (`func`) and gets a useful PTMF type. In `fails`, the expression does not refer to a `Decl` and its type is special, printed as `bound member function`. `Expr` provides a method for extracting the true type so we can use that in this situation. --------- Co-authored-by: Doug Wyatt <[email protected]> Co-authored-by: Sirraide <[email protected]>
1 parent f02b661 commit ccc4732

File tree

2 files changed

+36
-9
lines changed

2 files changed

+36
-9
lines changed

clang/lib/Sema/SemaFunctionEffects.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1208,8 +1208,16 @@ class Analyzer {
12081208
return true;
12091209
}
12101210

1211-
// No Decl, just an Expr. Just check based on its type.
1212-
checkIndirectCall(Call, CalleeExpr->getType());
1211+
// No Decl, just an Expr. Just check based on its type. Bound member
1212+
// functions are a special expression type and need to be specially
1213+
// unpacked.
1214+
QualType CalleeExprQT = CalleeExpr->getType();
1215+
if (CalleeExpr->isBoundMemberFunction(Outer.S.getASTContext())) {
1216+
QualType QT = Expr::findBoundMemberType(CalleeExpr);
1217+
if (!QT.isNull())
1218+
CalleeExprQT = QT;
1219+
}
1220+
checkIndirectCall(Call, CalleeExprQT);
12131221

12141222
return true;
12151223
}

clang/test/Sema/attr-nonblocking-constraints.cpp

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -235,16 +235,35 @@ void nb13() [[clang::nonblocking]] { nb12(); }
235235
// C++ member function pointers
236236
struct PTMFTester {
237237
typedef void (PTMFTester::*ConvertFunction)() [[clang::nonblocking]];
238-
239-
void convert() [[clang::nonblocking]];
238+
typedef void (PTMFTester::*BlockingFunction)();
240239

241240
ConvertFunction mConvertFunc;
242-
};
243241

244-
void PTMFTester::convert() [[clang::nonblocking]]
245-
{
246-
(this->*mConvertFunc)();
247-
}
242+
void convert() [[clang::nonblocking]]
243+
{
244+
(this->*mConvertFunc)(); // This should not generate a warning.
245+
}
246+
247+
template <typename T>
248+
struct Holder {
249+
T value;
250+
251+
T& operator*() { return value; }
252+
};
253+
254+
255+
void ptmfInExpr(Holder<ConvertFunction>& holder) [[clang::nonblocking]]
256+
{
257+
(this->*(*holder))(); // Should not generate a warning.
258+
((*this).*(*holder))(); // Should not generate a warning.
259+
}
260+
261+
void ptmfInExpr(Holder<BlockingFunction>& holder) [[clang::nonblocking]]
262+
{
263+
(this->*(*holder))(); // expected-warning {{function with 'nonblocking' attribute must not call non-'nonblocking' expression}}
264+
((*this).*(*holder))(); // expected-warning {{function with 'nonblocking' attribute must not call non-'nonblocking' expression}}
265+
}
266+
};
248267

249268
// Allow implicit conversion from array to pointer.
250269
void nb14(unsigned idx) [[clang::nonblocking]]

0 commit comments

Comments
 (0)