[clang] 7f9d348 - [Clang] SemaFunctionEffects: When verifying a function, ignore any trailing `requires` clause. (#114266)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Nov 5 01:51:06 PST 2024
Author: Doug Wyatt
Date: 2024-11-05T10:51:01+01:00
New Revision: 7f9d348eb2a54a2dd07ad9e029baef30d9d9b737
URL: https://github.com/llvm/llvm-project/commit/7f9d348eb2a54a2dd07ad9e029baef30d9d9b737
DIFF: https://github.com/llvm/llvm-project/commit/7f9d348eb2a54a2dd07ad9e029baef30d9d9b737.diff
LOG: [Clang] SemaFunctionEffects: When verifying a function, ignore any trailing `requires` clause. (#114266)
---------
Co-authored-by: Doug Wyatt <dwyatt at apple.com>
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 3fa326db06ee41..ab728f24d8a271 100644
--- a/clang/lib/Sema/SemaFunctionEffects.cpp
+++ b/clang/lib/Sema/SemaFunctionEffects.cpp
@@ -971,6 +971,7 @@ class Analyzer {
PendingFunctionAnalysis &CurrentFunction;
CallableInfo &CurrentCaller;
ViolationSite VSite;
+ const Expr *TrailingRequiresClause = nullptr;
FunctionBodyASTVisitor(Analyzer &Outer,
PendingFunctionAnalysis &CurrentFunction,
@@ -985,6 +986,9 @@ class Analyzer {
if (auto *Dtor = dyn_cast<CXXDestructorDecl>(CurrentCaller.CDecl))
followDestructor(dyn_cast<CXXRecordDecl>(Dtor->getParent()), Dtor);
+ if (auto *FD = dyn_cast<FunctionDecl>(CurrentCaller.CDecl))
+ TrailingRequiresClause = FD->getTrailingRequiresClause();
+
// Do an AST traversal of the function/block body
TraverseDecl(const_cast<Decl *>(CurrentCaller.CDecl));
}
@@ -1259,6 +1263,17 @@ class Analyzer {
return true;
}
+ bool TraverseStmt(Stmt *Statement) {
+ // If this statement is a `requires` clause from the top-level function
+ // being traversed, ignore it, since it's not generating runtime code.
+ // We skip the traversal of lambdas (beyond their captures, see
+ // TraverseLambdaExpr below), so just caching this from our constructor
+ // should suffice.
+ if (Statement != TrailingRequiresClause)
+ return Base::TraverseStmt(Statement);
+ return true;
+ }
+
bool TraverseConstructorInitializer(CXXCtorInitializer *Init) {
ViolationSite PrevVS = VSite;
if (Init->isAnyMemberInitializer())
@@ -1297,6 +1312,7 @@ class Analyzer {
}
bool TraverseBlockExpr(BlockExpr * /*unused*/) {
+ // As with lambdas, don't traverse the block's body.
// TODO: are the capture expressions (ctor call?) safe?
return true;
}
diff --git a/clang/test/Sema/attr-nonblocking-constraints.cpp b/clang/test/Sema/attr-nonblocking-constraints.cpp
index f23093d4dc8a96..19a4c3b7942b12 100644
--- a/clang/test/Sema/attr-nonblocking-constraints.cpp
+++ b/clang/test/Sema/attr-nonblocking-constraints.cpp
@@ -388,6 +388,51 @@ void nb26() [[clang::nonblocking]] {
abort_wrapper(); // no diagnostic
}
+// --- Make sure we don't traverse a requires clause. ---
+
+// Apparently some requires clauses are able to be collapsed into a constant before the nonblocking
+// analysis sees any function calls. This example (extracted from a real-world case where
+// `operator&&` in <valarray>, preceding the inclusion of <expected>) is sufficiently complex
+// to look like it contains function calls. There may be simpler examples.
+
+namespace ExpectedTest {
+
+template <class _Tp>
+inline constexpr bool is_copy_constructible_v = __is_constructible(_Tp, _Tp&);
+
+template <bool, class _Tp = void>
+struct enable_if {};
+template <class _Tp>
+struct enable_if<true, _Tp> {
+ typedef _Tp type;
+};
+
+template <bool _Bp, class _Tp = void>
+using enable_if_t = typename enable_if<_Bp, _Tp>::type;
+
+// Doesn't seem to matter whether the enable_if is true or false.
+template <class E1, class E2, enable_if_t<is_copy_constructible_v<E1>> = 0>
+inline bool operator&&(const E1& x, const E2& y);
+
+template <class _Tp, class _Err>
+class expected {
+public:
+ constexpr expected()
+ {}
+
+ constexpr expected(const expected&)
+ requires(is_copy_constructible_v<_Tp> && is_copy_constructible_v<_Err>)
+ = default;
+};
+
+void test() [[clang::nonblocking]]
+{
+ expected<int, int> a;
+ auto b = a;
+}
+
+} // namespace ExpectedTest
+
// --- nonblocking implies noexcept ---
#pragma clang diagnostic warning "-Wperf-constraint-implies-noexcept"
More information about the cfe-commits
mailing list