[clang] [Clang] SemaFunctionEffects: When verifying a function, ignore any conditional noexcept expression. (PR #115342)

via cfe-commits cfe-commits at lists.llvm.org
Thu Nov 7 09:08:37 PST 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Doug Wyatt (dougsonos)

<details>
<summary>Changes</summary>

Would have been part of my last PR (#<!-- -->142666) if I'd found it a few hours sooner.

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


2 Files Affected:

- (modified) clang/lib/Sema/SemaFunctionEffects.cpp (+17-2) 
- (modified) clang/test/Sema/attr-nonblocking-constraints.cpp (+10-2) 


``````````diff
diff --git a/clang/lib/Sema/SemaFunctionEffects.cpp b/clang/lib/Sema/SemaFunctionEffects.cpp
index ab728f24d8a271..70f6f9b6784cd8 100644
--- a/clang/lib/Sema/SemaFunctionEffects.cpp
+++ b/clang/lib/Sema/SemaFunctionEffects.cpp
@@ -972,6 +972,7 @@ class Analyzer {
     CallableInfo &CurrentCaller;
     ViolationSite VSite;
     const Expr *TrailingRequiresClause = nullptr;
+    const Expr *NoexceptExpr = nullptr;
 
     FunctionBodyASTVisitor(Analyzer &Outer,
                            PendingFunctionAnalysis &CurrentFunction,
@@ -986,9 +987,22 @@ 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))
+      if (auto *FD = dyn_cast<FunctionDecl>(CurrentCaller.CDecl)) {
         TrailingRequiresClause = FD->getTrailingRequiresClause();
 
+        // Note that FD->getType->getAs<FunctionProtoType>() can yield a
+        // noexcept Expr which has been boiled down to a constant expression.
+        // Going through the TypeSourceInfo obtains the actual expression which
+        // will be traversed as part of the function -- unless we capture it
+        // here and have TraverseStmt skip it.
+        if (TypeSourceInfo *TSI = FD->getTypeSourceInfo()) {
+          FunctionProtoTypeLoc TL =
+              TSI->getTypeLoc().getAs<FunctionProtoTypeLoc>();
+          if (const FunctionProtoType *FPT = TL.getTypePtr())
+            NoexceptExpr = FPT->getNoexceptExpr();
+        }
+      }
+
       // Do an AST traversal of the function/block body
       TraverseDecl(const_cast<Decl *>(CurrentCaller.CDecl));
     }
@@ -1269,7 +1283,8 @@ class Analyzer {
       // We skip the traversal of lambdas (beyond their captures, see
       // TraverseLambdaExpr below), so just caching this from our constructor
       // should suffice.
-      if (Statement != TrailingRequiresClause)
+      // The exact same is true for a conditional `noexcept()` clause.
+      if (Statement != TrailingRequiresClause && Statement != NoexceptExpr)
         return Base::TraverseStmt(Statement);
       return true;
     }
diff --git a/clang/test/Sema/attr-nonblocking-constraints.cpp b/clang/test/Sema/attr-nonblocking-constraints.cpp
index 19a4c3b7942b12..169c42ee35fe83 100644
--- a/clang/test/Sema/attr-nonblocking-constraints.cpp
+++ b/clang/test/Sema/attr-nonblocking-constraints.cpp
@@ -388,7 +388,7 @@ void nb26() [[clang::nonblocking]] {
 	abort_wrapper(); // no diagnostic
 }
 
-// --- Make sure we don't traverse a requires clause. ---
+// --- Make sure we don't traverse requires and noexcept clauses. ---
 
 // 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
@@ -420,7 +420,9 @@ class expected {
   constexpr expected()
     {}
 
+  // This is a deliberate corruption of the real implementation for simplicity.
   constexpr expected(const expected&)
+    noexcept(is_copy_constructible_v<_Tp> && is_copy_constructible_v<_Err>)
     requires(is_copy_constructible_v<_Tp> && is_copy_constructible_v<_Err>)
   = default;
 };
@@ -428,11 +430,17 @@ class expected {
 void test() [[clang::nonblocking]]
 {
 	expected<int, int> a;
-	auto b = a;
+	auto b = a;            // Copy constructor.
 }
 
 } // namespace ExpectedTest
 
+// Make sure that simple type traits don't cause violations.
+
+void nb27() [[clang::nonblocking]] {
+	bool x = __is_constructible(int, const int&);
+}
+
 // --- nonblocking implies noexcept ---
 #pragma clang diagnostic warning "-Wperf-constraint-implies-noexcept"
 

``````````

</details>


https://github.com/llvm/llvm-project/pull/115342


More information about the cfe-commits mailing list