[clang] [clang] SemaFunctionEffects: When verifying a function, ignore any trailing 'requires' clause. (PR #114266)

Doug Wyatt via cfe-commits cfe-commits at lists.llvm.org
Wed Oct 30 10:06:53 PDT 2024


https://github.com/dougsonos created https://github.com/llvm/llvm-project/pull/114266

Clearly there's an omission here, that a trailing `requires` clause in a called function is being subject to effect analysis.

But despite many hours of effort I haven't been able to create a self-contained reproducer. My best effort:

```c++
#include <valarray>
#include <type_traits>
#include <expected>

template <class _Tp, _Tp __v>
struct integral_constant {
  static constexpr _Tp value = __v;
  typedef _Tp value_type;
  typedef integral_constant type;
  constexpr operator value_type() const noexcept { return value; }
  constexpr value_type operator()() const noexcept { return value; }
};

template <typename T>
struct IsInt : public integral_constant<bool, false> {};

template <>
struct IsInt<int> : public integral_constant<bool, true> {};

template <typename T>
inline constexpr bool IsInt_V = IsInt<T>::value;

template <typename T, typename E>
struct ExpectedLike {
	ExpectedLike() = default;
	
	constexpr ExpectedLike(const ExpectedLike&)
// 	requires(IsInt_V<T> && IsInt_V<E> && IsInt_V<T>)
    requires(std::is_copy_constructible_v<T> && std::is_copy_constructible_v<E> && std::is_trivially_copy_constructible_v<T> &&
             std::is_trivially_copy_constructible_v<E>)

	= default;
	
};

void nb_xx() [[clang::nonblocking]]
{
	ExpectedLike<int, int> a;
	auto b = a;
// No warning. I don't know why.

	std::expected<int, int> c;
	std::expected<int, int> d = c;
// ^^ warning: function with 'nonblocking' attribute must not call non-'nonblocking' constructor 'std::expected<int, int>::expected' [-Wfunction-effects]
}
```

The two elements of the mystery are:

- why doesn't my `ExpectedLike<T, E>` copy constructor reproduce the behavior of `std::expected<T, E>`?
- why does reproduction with `std::expected` depend on the global `operator &&` in `<valarray>`?

I've verified that the change to SemaFunctionEffects fixes the issue, but I'd sure like to be able to construct a self-contained test.

>From 6a8a3f21eb23b8b7d63bd8b0fb6e2e85ff1951df Mon Sep 17 00:00:00 2001
From: Doug Wyatt <dwyatt at apple.com>
Date: Wed, 30 Oct 2024 09:53:58 -0700
Subject: [PATCH] [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())



More information about the cfe-commits mailing list