https://github.com/dougsonos updated https://github.com/llvm/llvm-project/pull/114266
>From 6a8a3f21eb23b8b7d63bd8b0fb6e2e85ff1951df Mon Sep 17 00:00:00 2001 From: Doug Wyatt <dwy...@apple.com> Date: Wed, 30 Oct 2024 09:53:58 -0700 Subject: [PATCH 1/2] [clang] SemaFunctionEffects: When verifying a function, ignore any trailing 'requires' clause. --- clang/lib/Sema/SemaFunctionEffects.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/clang/lib/Sema/SemaFunctionEffects.cpp b/clang/lib/Sema/SemaFunctionEffects.cpp index 3fa326db06ee41..f7ff8b92d8a929 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,12 @@ class Analyzer { return true; } + bool TraverseStmt(Stmt *Statement) { + if (Statement != TrailingRequiresClause) + return Base::TraverseStmt(Statement); + return true; + } + bool TraverseConstructorInitializer(CXXCtorInitializer *Init) { ViolationSite PrevVS = VSite; if (Init->isAnyMemberInitializer()) >From 9de0cf0c514c9dc3bc0b282bab6ec52d3c8156b4 Mon Sep 17 00:00:00 2001 From: Doug Wyatt <dwy...@apple.com> Date: Sat, 2 Nov 2024 09:03:48 -0700 Subject: [PATCH 2/2] Add a test. --- .../Sema/attr-nonblocking-constraints.cpp | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) 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" _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits