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 <dwy...@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" _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits