llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Doug Wyatt (dougsonos)
<details>
<summary>Changes</summary>
This example is reduced from a discovery: resetting a shared pointer from a
nonblocking function is not diagnosed.
```
void nb23()
{
struct X {
int *ptr = nullptr;
X() {}
~X() { delete ptr; }
};
auto inner = []() [[clang::nonblocking]] {
X();
};
}
```
`shared_ptr<T>::reset()` creates a temporary `shared_ptr` and swaps it
with its current state. The temporary `shared_ptr` constructor is nonblocking
but its destructor potentially deallocates memory and is unsafe.
Analysis was ignoring the implicit call in the AST to destroy the temporary.
---
Full diff: https://github.com/llvm/llvm-project/pull/166110.diff
2 Files Affected:
- (modified) clang/lib/Sema/SemaFunctionEffects.cpp (+8)
- (modified) clang/test/Sema/attr-nonblocking-constraints.cpp (+14)
``````````diff
diff --git a/clang/lib/Sema/SemaFunctionEffects.cpp
b/clang/lib/Sema/SemaFunctionEffects.cpp
index 8590ee831084f..468f157f2e0bd 100644
--- a/clang/lib/Sema/SemaFunctionEffects.cpp
+++ b/clang/lib/Sema/SemaFunctionEffects.cpp
@@ -1271,7 +1271,15 @@ class Analyzer {
const CXXConstructorDecl *Ctor = Construct->getConstructor();
CallableInfo CI(*Ctor);
followCall(CI, Construct->getLocation());
+ return true;
+ }
+ bool VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *BTE) override {
+ const CXXDestructorDecl* Dtor = BTE->getTemporary()->getDestructor();
+ if (Dtor != nullptr) {
+ CallableInfo CI(*Dtor);
+ followCall(CI, BTE->getBeginLoc());
+ }
return true;
}
diff --git a/clang/test/Sema/attr-nonblocking-constraints.cpp
b/clang/test/Sema/attr-nonblocking-constraints.cpp
index b26a945843696..4b831c0a6be09 100644
--- a/clang/test/Sema/attr-nonblocking-constraints.cpp
+++ b/clang/test/Sema/attr-nonblocking-constraints.cpp
@@ -354,6 +354,20 @@ struct Unsafe {
Unsafe(float y) [[clang::nonblocking]] : Unsafe(int(y)) {} //
expected-warning {{constructor with 'nonblocking' attribute must not call
non-'nonblocking' constructor 'Unsafe::Unsafe'}}
};
+// Exercise the case of a temporary with a safe constructor and unsafe
destructor.
+void nb23()
+{
+ struct X {
+ int *ptr = nullptr;
+ X() {}
+ ~X() { delete ptr; } // expected-note {{destructor cannot be
inferred 'nonblocking' because it allocates or deallocates memory}}
+ };
+
+ auto inner = []() [[clang::nonblocking]] {
+ X(); // expected-warning {{lambda with 'nonblocking' attribute
must not call non-'nonblocking' destructor 'nb23()::X::~X'}}
+ };
+}
+
struct DerivedFromUnsafe : public Unsafe {
DerivedFromUnsafe() [[clang::nonblocking]] {} // expected-warning
{{constructor with 'nonblocking' attribute must not call non-'nonblocking'
constructor 'Unsafe::Unsafe'}}
DerivedFromUnsafe(int x) [[clang::nonblocking]] : Unsafe(x) {} //
expected-warning {{constructor with 'nonblocking' attribute must not call
non-'nonblocking' constructor 'Unsafe::Unsafe'}}
``````````
</details>
https://github.com/llvm/llvm-project/pull/166110
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits