Author: Doug Wyatt
Date: 2025-11-03T12:26:49-08:00
New Revision: ccc473254fd2d0da01921e8402fbd4f678ff46f1

URL: 
https://github.com/llvm/llvm-project/commit/ccc473254fd2d0da01921e8402fbd4f678ff46f1
DIFF: 
https://github.com/llvm/llvm-project/commit/ccc473254fd2d0da01921e8402fbd4f678ff46f1.diff

LOG: [Clang] FunctionEffects: properly extract the type of a bound member 
member function from a CallExpr. (#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]>

Added: 
    

Modified: 
    clang/lib/Sema/SemaFunctionEffects.cpp
    clang/test/Sema/attr-nonblocking-constraints.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Sema/SemaFunctionEffects.cpp 
b/clang/lib/Sema/SemaFunctionEffects.cpp
index 8590ee831084f..5459861ec349d 100644
--- a/clang/lib/Sema/SemaFunctionEffects.cpp
+++ b/clang/lib/Sema/SemaFunctionEffects.cpp
@@ -1208,8 +1208,16 @@ class Analyzer {
         return true;
       }
 
-      // No Decl, just an Expr. Just check based on its type.
-      checkIndirectCall(Call, CalleeExpr->getType());
+      // No Decl, just an Expr. Just check based on its type. Bound member
+      // functions are a special expression type and need to be specially
+      // unpacked.
+      QualType CalleeExprQT = CalleeExpr->getType();
+      if (CalleeExpr->isBoundMemberFunction(Outer.S.getASTContext())) {
+        QualType QT = Expr::findBoundMemberType(CalleeExpr);
+        if (!QT.isNull())
+          CalleeExprQT = QT;
+      }
+      checkIndirectCall(Call, CalleeExprQT);
 
       return true;
     }

diff  --git a/clang/test/Sema/attr-nonblocking-constraints.cpp 
b/clang/test/Sema/attr-nonblocking-constraints.cpp
index b26a945843696..0d2dbb4947dc8 100644
--- a/clang/test/Sema/attr-nonblocking-constraints.cpp
+++ b/clang/test/Sema/attr-nonblocking-constraints.cpp
@@ -235,16 +235,35 @@ void nb13() [[clang::nonblocking]] { nb12(); }
 // C++ member function pointers
 struct PTMFTester {
        typedef void (PTMFTester::*ConvertFunction)() [[clang::nonblocking]];
-
-       void convert() [[clang::nonblocking]];
+       typedef void (PTMFTester::*BlockingFunction)();
 
        ConvertFunction mConvertFunc;
-};
 
-void PTMFTester::convert() [[clang::nonblocking]]
-{
-       (this->*mConvertFunc)();
-}
+       void convert() [[clang::nonblocking]]
+       {
+               (this->*mConvertFunc)(); // This should not generate a warning.
+       }
+
+       template <typename T>
+       struct Holder {
+               T value;
+               
+               T& operator*() { return value; }
+       };
+
+
+       void ptmfInExpr(Holder<ConvertFunction>& holder) [[clang::nonblocking]]
+       {
+               (this->*(*holder))();   // Should not generate a warning.
+               ((*this).*(*holder))(); // Should not generate a warning.
+       }
+
+       void ptmfInExpr(Holder<BlockingFunction>& holder) [[clang::nonblocking]]
+       {
+               (this->*(*holder))(); // expected-warning {{function with 
'nonblocking' attribute must not call non-'nonblocking' expression}}
+               ((*this).*(*holder))(); // expected-warning {{function with 
'nonblocking' attribute must not call non-'nonblocking' expression}}
+       }
+};
 
 // Allow implicit conversion from array to pointer.
 void nb14(unsigned idx) [[clang::nonblocking]]


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to