Skip to content

Conversation

@higher-performance
Copy link
Contributor

  1. Handle transformed awaitables for AllowedCallees, which generate temporaries and weren't being handled by Add the ability to exempt callees from the misc-coroutine-hostile-raii clang-tidy check #167778.

  2. Fix name mismatches in storeOptions.

@llvmbot
Copy link
Member

llvmbot commented Nov 13, 2025

@llvm/pr-subscribers-clang-tidy

Author: None (higher-performance)

Changes
  1. Handle transformed awaitables for AllowedCallees, which generate temporaries and weren't being handled by #167778.

  2. Fix name mismatches in storeOptions.


Full diff: https://github.com/llvm/llvm-project/pull/167947.diff

2 Files Affected:

  • (modified) clang-tools-extra/clang-tidy/misc/CoroutineHostileRAIICheck.cpp (+9-5)
  • (modified) clang-tools-extra/test/clang-tidy/checkers/misc/coroutine-hostile-raii.cpp (+10-2)
diff --git a/clang-tools-extra/clang-tidy/misc/CoroutineHostileRAIICheck.cpp b/clang-tools-extra/clang-tidy/misc/CoroutineHostileRAIICheck.cpp
index a7b74944690b4..c7001d4eebfed 100644
--- a/clang-tools-extra/clang-tidy/misc/CoroutineHostileRAIICheck.cpp
+++ b/clang-tools-extra/clang-tidy/misc/CoroutineHostileRAIICheck.cpp
@@ -67,6 +67,11 @@ static auto typeWithNameIn(const std::vector<StringRef> &Names) {
       hasCanonicalType(hasDeclaration(namedDecl(hasAnyName(Names)))));
 }
 
+static auto functionWithNameIn(const std::vector<StringRef> &Names) {
+  auto call = callExpr(callee(functionDecl(hasAnyName(Names))));
+  return anyOf(expr(cxxBindTemporaryExpr(has(call))), expr(call));
+}
+
 CoroutineHostileRAIICheck::CoroutineHostileRAIICheck(StringRef Name,
                                                      ClangTidyContext *Context)
     : ClangTidyCheck(Name, Context),
@@ -83,9 +88,8 @@ void CoroutineHostileRAIICheck::registerMatchers(MatchFinder *Finder) {
                                     hasAttr(attr::Kind::ScopedLockable)))))
                             .bind("scoped-lockable");
   auto OtherRAII = varDecl(typeWithNameIn(RAIITypesList)).bind("raii");
-  auto AllowedSuspend = awaitable(
-      anyOf(typeWithNameIn(AllowedAwaitablesList),
-            callExpr(callee(functionDecl(hasAnyName(AllowedCallees))))));
+  auto AllowedSuspend = awaitable(anyOf(typeWithNameIn(AllowedAwaitablesList),
+                                        functionWithNameIn(AllowedCallees)));
   Finder->addMatcher(
       expr(anyOf(coawaitExpr(unless(AllowedSuspend)), coyieldExpr()),
            forEachPrevStmt(
@@ -113,9 +117,9 @@ void CoroutineHostileRAIICheck::storeOptions(
     ClangTidyOptions::OptionMap &Opts) {
   Options.store(Opts, "RAIITypesList",
                 utils::options::serializeStringList(RAIITypesList));
-  Options.store(Opts, "SafeAwaitableList",
+  Options.store(Opts, "AllowedAwaitablesList",
                 utils::options::serializeStringList(AllowedAwaitablesList));
-  Options.store(Opts, "SafeCallees",
+  Options.store(Opts, "AllowedCallees",
                 utils::options::serializeStringList(AllowedCallees));
 }
 } // namespace clang::tidy::misc
diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/coroutine-hostile-raii.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/coroutine-hostile-raii.cpp
index ec6ddec56e1f2..dff73aeb7a5ee 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/misc/coroutine-hostile-raii.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/misc/coroutine-hostile-raii.cpp
@@ -2,7 +2,7 @@
 // RUN:   -config="{CheckOptions: {\
 // RUN:             misc-coroutine-hostile-raii.RAIITypesList: 'my::Mutex; ::my::other::Mutex', \
 // RUN:             misc-coroutine-hostile-raii.AllowedAwaitablesList: 'safe::awaitable; ::transformable::awaitable', \
-// RUN:             misc-coroutine-hostile-raii.AllowedCallees: 'safe::AwaitFunc; ::safe::Obj::AwaitMethod' \
+// RUN:             misc-coroutine-hostile-raii.AllowedCallees: 'safe::AwaitFunc; ::safe::Obj::AwaitMethod; retExemptedAwaitable' \
 // RUN:             }}"
 
 namespace std {
@@ -163,7 +163,10 @@ ReturnObject RAIISafeSuspendTest() {
 // ================================================================================
 // Safe transformable awaitable
 // ================================================================================
-struct transformable { struct awaitable{}; };
+struct transformable {
+  struct awaitable{};
+  struct unsafe_awaitable{};
+};
 using alias_transformable_awaitable = transformable::awaitable;
 struct UseTransformAwaitable {
   struct promise_type {
@@ -172,13 +175,18 @@ struct UseTransformAwaitable {
     std::suspend_always final_suspend() noexcept { return {}; }
     void unhandled_exception() {}
     std::suspend_always await_transform(transformable::awaitable) { return {}; }
+    std::suspend_always await_transform(transformable::unsafe_awaitable) {
+      return {};
+    }
   };
 };
 
 auto retAwaitable() { return transformable::awaitable{}; }
+auto retExemptedAwaitable() { return transformable::unsafe_awaitable{}; }
 UseTransformAwaitable RAIISafeSuspendTest2() {
   absl::Mutex a;
   co_await retAwaitable();
+  co_await retExemptedAwaitable();
   co_await transformable::awaitable{};
   co_await alias_transformable_awaitable{};
 }

@llvmbot
Copy link
Member

llvmbot commented Nov 13, 2025

@llvm/pr-subscribers-clang-tools-extra

Author: None (higher-performance)

Changes
  1. Handle transformed awaitables for AllowedCallees, which generate temporaries and weren't being handled by #167778.

  2. Fix name mismatches in storeOptions.


Full diff: https://github.com/llvm/llvm-project/pull/167947.diff

2 Files Affected:

  • (modified) clang-tools-extra/clang-tidy/misc/CoroutineHostileRAIICheck.cpp (+9-5)
  • (modified) clang-tools-extra/test/clang-tidy/checkers/misc/coroutine-hostile-raii.cpp (+10-2)
diff --git a/clang-tools-extra/clang-tidy/misc/CoroutineHostileRAIICheck.cpp b/clang-tools-extra/clang-tidy/misc/CoroutineHostileRAIICheck.cpp
index a7b74944690b4..c7001d4eebfed 100644
--- a/clang-tools-extra/clang-tidy/misc/CoroutineHostileRAIICheck.cpp
+++ b/clang-tools-extra/clang-tidy/misc/CoroutineHostileRAIICheck.cpp
@@ -67,6 +67,11 @@ static auto typeWithNameIn(const std::vector<StringRef> &Names) {
       hasCanonicalType(hasDeclaration(namedDecl(hasAnyName(Names)))));
 }
 
+static auto functionWithNameIn(const std::vector<StringRef> &Names) {
+  auto call = callExpr(callee(functionDecl(hasAnyName(Names))));
+  return anyOf(expr(cxxBindTemporaryExpr(has(call))), expr(call));
+}
+
 CoroutineHostileRAIICheck::CoroutineHostileRAIICheck(StringRef Name,
                                                      ClangTidyContext *Context)
     : ClangTidyCheck(Name, Context),
@@ -83,9 +88,8 @@ void CoroutineHostileRAIICheck::registerMatchers(MatchFinder *Finder) {
                                     hasAttr(attr::Kind::ScopedLockable)))))
                             .bind("scoped-lockable");
   auto OtherRAII = varDecl(typeWithNameIn(RAIITypesList)).bind("raii");
-  auto AllowedSuspend = awaitable(
-      anyOf(typeWithNameIn(AllowedAwaitablesList),
-            callExpr(callee(functionDecl(hasAnyName(AllowedCallees))))));
+  auto AllowedSuspend = awaitable(anyOf(typeWithNameIn(AllowedAwaitablesList),
+                                        functionWithNameIn(AllowedCallees)));
   Finder->addMatcher(
       expr(anyOf(coawaitExpr(unless(AllowedSuspend)), coyieldExpr()),
            forEachPrevStmt(
@@ -113,9 +117,9 @@ void CoroutineHostileRAIICheck::storeOptions(
     ClangTidyOptions::OptionMap &Opts) {
   Options.store(Opts, "RAIITypesList",
                 utils::options::serializeStringList(RAIITypesList));
-  Options.store(Opts, "SafeAwaitableList",
+  Options.store(Opts, "AllowedAwaitablesList",
                 utils::options::serializeStringList(AllowedAwaitablesList));
-  Options.store(Opts, "SafeCallees",
+  Options.store(Opts, "AllowedCallees",
                 utils::options::serializeStringList(AllowedCallees));
 }
 } // namespace clang::tidy::misc
diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/coroutine-hostile-raii.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/coroutine-hostile-raii.cpp
index ec6ddec56e1f2..dff73aeb7a5ee 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/misc/coroutine-hostile-raii.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/misc/coroutine-hostile-raii.cpp
@@ -2,7 +2,7 @@
 // RUN:   -config="{CheckOptions: {\
 // RUN:             misc-coroutine-hostile-raii.RAIITypesList: 'my::Mutex; ::my::other::Mutex', \
 // RUN:             misc-coroutine-hostile-raii.AllowedAwaitablesList: 'safe::awaitable; ::transformable::awaitable', \
-// RUN:             misc-coroutine-hostile-raii.AllowedCallees: 'safe::AwaitFunc; ::safe::Obj::AwaitMethod' \
+// RUN:             misc-coroutine-hostile-raii.AllowedCallees: 'safe::AwaitFunc; ::safe::Obj::AwaitMethod; retExemptedAwaitable' \
 // RUN:             }}"
 
 namespace std {
@@ -163,7 +163,10 @@ ReturnObject RAIISafeSuspendTest() {
 // ================================================================================
 // Safe transformable awaitable
 // ================================================================================
-struct transformable { struct awaitable{}; };
+struct transformable {
+  struct awaitable{};
+  struct unsafe_awaitable{};
+};
 using alias_transformable_awaitable = transformable::awaitable;
 struct UseTransformAwaitable {
   struct promise_type {
@@ -172,13 +175,18 @@ struct UseTransformAwaitable {
     std::suspend_always final_suspend() noexcept { return {}; }
     void unhandled_exception() {}
     std::suspend_always await_transform(transformable::awaitable) { return {}; }
+    std::suspend_always await_transform(transformable::unsafe_awaitable) {
+      return {};
+    }
   };
 };
 
 auto retAwaitable() { return transformable::awaitable{}; }
+auto retExemptedAwaitable() { return transformable::unsafe_awaitable{}; }
 UseTransformAwaitable RAIISafeSuspendTest2() {
   absl::Mutex a;
   co_await retAwaitable();
+  co_await retExemptedAwaitable();
   co_await transformable::awaitable{};
   co_await alias_transformable_awaitable{};
 }

@github-actions
Copy link

github-actions bot commented Nov 13, 2025

✅ With the latest revision this PR passed the C/C++ code linter.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants