From 0ab16b664773bd7b3859ec9e6fc84217dbac1de9 Mon Sep 17 00:00:00 2001 From: Doug Wyatt Date: Sun, 2 Nov 2025 15:55:48 -0800 Subject: [PATCH 1/4] [Clang] FunctionEffect analysis was missing a CXXBindTemporaryExpr's implicit call to a destructor. --- clang/lib/Sema/SemaFunctionEffects.cpp | 8 ++++++++ clang/test/Sema/attr-nonblocking-constraints.cpp | 14 ++++++++++++++ 2 files changed, 22 insertions(+) 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'}} From f7bb4a279569f2fa742fe18e80ad04bbb0e92b5b Mon Sep 17 00:00:00 2001 From: Doug Wyatt Date: Sun, 2 Nov 2025 16:19:51 -0800 Subject: [PATCH 2/4] format --- clang/lib/Sema/SemaFunctionEffects.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/Sema/SemaFunctionEffects.cpp b/clang/lib/Sema/SemaFunctionEffects.cpp index 468f157f2e0bd..d68158f8425d8 100644 --- a/clang/lib/Sema/SemaFunctionEffects.cpp +++ b/clang/lib/Sema/SemaFunctionEffects.cpp @@ -1275,7 +1275,7 @@ class Analyzer { } bool VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *BTE) override { - const CXXDestructorDecl* Dtor = BTE->getTemporary()->getDestructor(); + const CXXDestructorDecl *Dtor = BTE->getTemporary()->getDestructor(); if (Dtor != nullptr) { CallableInfo CI(*Dtor); followCall(CI, BTE->getBeginLoc()); From b4c8284d75d9530a57541f69ba5acdf6b57bbcc4 Mon Sep 17 00:00:00 2001 From: Doug Wyatt Date: Mon, 3 Nov 2025 08:54:54 -0800 Subject: [PATCH 3/4] more tests --- .../test/Sema/attr-nonblocking-constraints.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/clang/test/Sema/attr-nonblocking-constraints.cpp b/clang/test/Sema/attr-nonblocking-constraints.cpp index 4b831c0a6be09..3b62ab545bf58 100644 --- a/clang/test/Sema/attr-nonblocking-constraints.cpp +++ b/clang/test/Sema/attr-nonblocking-constraints.cpp @@ -354,18 +354,31 @@ 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. +// Exercise cases 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}} + ~X() { delete ptr; } // expected-note 2 {{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'}} }; + + auto inner2 = [](X x) [[clang::nonblocking]] { // expected-warning {{lambda with 'nonblocking' attribute must not call non-'nonblocking' destructor 'nb23()::X::~X'}} + }; + +} + +struct S2 { ~S2(); }; // expected-note 2 {{declaration cannot be inferred 'nonblocking' because it has no definition in this translation unit}} +void nb24() { + S2 s; + [&]() [[clang::nonblocking]] { + [s]{ auto x = &s; }(); // expected-warning {{lambda with 'nonblocking' attribute must not call non-'nonblocking' destructor}} expected-note {{destructor cannot be inferred 'nonblocking' because it calls non-'nonblocking' destructor 'S2::~S2'}} + [=]{ auto x = &s; }(); // expected-warning {{lambda with 'nonblocking' attribute must not call non-'nonblocking' destructor}} expected-note {{destructor cannot be inferred 'nonblocking' because it calls non-'nonblocking' destructor 'S2::~S2'}} + }(); } struct DerivedFromUnsafe : public Unsafe { From 2b688759c1fd764c40596aaad8d50bf0f88f550b Mon Sep 17 00:00:00 2001 From: Doug Wyatt Date: Mon, 3 Nov 2025 12:36:12 -0800 Subject: [PATCH 4/4] add a release note --- clang/docs/ReleaseNotes.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 92fc9381a5868..f6a67e853e371 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -452,6 +452,7 @@ Bug Fixes to Attribute Support - Fix a crash when the function name is empty in the `swift_name` attribute. (#GH157075) - Fixes crashes or missing diagnostics with the `device_kernel` attribute. (#GH161905) - Fix handling of parameter indexes when an attribute is applied to a C++23 explicit object member function. +- Fixed several false positives and false negatives in function effect (`nonblocking`) analysis. (#GH166078) (#GH166101) (#GH166110) Bug Fixes to C++ Support ^^^^^^^^^^^^^^^^^^^^^^^^