[clang] [Clang] SemaFunctionEffects: When verifying a function, ignore any conditional noexcept expression. (PR #115342)
Doug Wyatt via cfe-commits
cfe-commits at lists.llvm.org
Fri Nov 8 12:12:17 PST 2024
https://github.com/dougsonos updated https://github.com/llvm/llvm-project/pull/115342
>From a0b6093fcf24ade7ce9ee0c3d65f679a41751225 Mon Sep 17 00:00:00 2001
From: Doug Wyatt <dwyatt at apple.com>
Date: Tue, 5 Nov 2024 13:35:50 -0800
Subject: [PATCH 1/2] [Clang] SemaFunctionEffects: When verifying a function,
ignore any conditional noexcept expression.
---
clang/lib/Sema/SemaFunctionEffects.cpp | 19 +++++++++++++++++--
.../Sema/attr-nonblocking-constraints.cpp | 12 ++++++++++--
2 files changed, 27 insertions(+), 4 deletions(-)
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"
>From 02f1fc7974fffb97b9f23d7fb072f23bd9bdd89a Mon Sep 17 00:00:00 2001
From: Doug Wyatt <dwyatt at apple.com>
Date: Fri, 8 Nov 2024 09:22:33 -0800
Subject: [PATCH 2/2] Review feedback: Check for no-prototype. Simplify test.
---
clang/lib/Sema/SemaFunctionEffects.cpp | 8 ++++----
clang/test/Sema/attr-nonblocking-constraints.cpp | 8 +++++---
2 files changed, 9 insertions(+), 7 deletions(-)
diff --git a/clang/lib/Sema/SemaFunctionEffects.cpp b/clang/lib/Sema/SemaFunctionEffects.cpp
index 70f6f9b6784cd8..a76a0a41276896 100644
--- a/clang/lib/Sema/SemaFunctionEffects.cpp
+++ b/clang/lib/Sema/SemaFunctionEffects.cpp
@@ -996,10 +996,10 @@ class Analyzer {
// 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();
+ if (FunctionProtoTypeLoc TL =
+ TSI->getTypeLoc().getAs<FunctionProtoTypeLoc>())
+ if (const FunctionProtoType *FPT = TL.getTypePtr())
+ NoexceptExpr = FPT->getNoexceptExpr();
}
}
diff --git a/clang/test/Sema/attr-nonblocking-constraints.cpp b/clang/test/Sema/attr-nonblocking-constraints.cpp
index 169c42ee35fe83..cc9108c0a4fbd6 100644
--- a/clang/test/Sema/attr-nonblocking-constraints.cpp
+++ b/clang/test/Sema/attr-nonblocking-constraints.cpp
@@ -422,7 +422,6 @@ class 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;
};
@@ -435,9 +434,12 @@ void test() [[clang::nonblocking]]
} // namespace ExpectedTest
-// Make sure that simple type traits don't cause violations.
+// Make sure a function call in a noexcept() clause is ignored.
+constexpr bool foo() [[clang::nonblocking(false)]] { return true; }
+void nb27() noexcept(foo()) [[clang::nonblocking]] {}
-void nb27() [[clang::nonblocking]] {
+// Make sure that simple type traits don't cause violations.
+void nb28() [[clang::nonblocking]] {
bool x = __is_constructible(int, const int&);
}
More information about the cfe-commits
mailing list