[clang] [Clang] [Sema] Ensure noexcept(typeid(E)) checks if E throws when needed (PR #95846)
Mital Ashok via cfe-commits
cfe-commits at lists.llvm.org
Mon Jun 17 23:13:33 PDT 2024
https://github.com/MitalAshok updated https://github.com/llvm/llvm-project/pull/95846
>From 89da8b3bcc678430fe4225c723e87914f2c378cd Mon Sep 17 00:00:00 2001
From: Mital Ashok <mital at mitalashok.co.uk>
Date: Mon, 17 Jun 2024 21:48:57 +0100
Subject: [PATCH 1/3] [Clang] [Sema] Ensure noexcept(typeid(E)) checks if E
throws when needed
---
clang/lib/Sema/SemaExceptionSpec.cpp | 9 +++++++--
.../test/SemaCXX/cxx0x-noexcept-expression.cpp | 18 ++++++++++++++++++
2 files changed, 25 insertions(+), 2 deletions(-)
diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp
index 67e0c7c63909e..ef1128cedf994 100644
--- a/clang/lib/Sema/SemaExceptionSpec.cpp
+++ b/clang/lib/Sema/SemaExceptionSpec.cpp
@@ -1111,13 +1111,18 @@ static CanThrowResult canDynamicCastThrow(const CXXDynamicCastExpr *DC) {
}
static CanThrowResult canTypeidThrow(Sema &S, const CXXTypeidExpr *DC) {
- if (DC->isTypeOperand())
+ // Operand is not evaluated, cannot possibly throw
+ if (!DC->isPotentiallyEvaluated())
return CT_Cannot;
if (DC->isValueDependent())
return CT_Dependent;
- return DC->hasNullCheck() ? CT_Can : CT_Cannot;
+ // Can throw std::bad_typeid if a nullptr is dereferenced
+ if (DC->hasNullCheck())
+ return CT_Can;
+
+ return S.canThrow(DC->getExprOperand());
}
CanThrowResult Sema::canThrow(const Stmt *S) {
diff --git a/clang/test/SemaCXX/cxx0x-noexcept-expression.cpp b/clang/test/SemaCXX/cxx0x-noexcept-expression.cpp
index c2b2244c117a0..1e86a31fffcbf 100644
--- a/clang/test/SemaCXX/cxx0x-noexcept-expression.cpp
+++ b/clang/test/SemaCXX/cxx0x-noexcept-expression.cpp
@@ -1,6 +1,10 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++2a %s -fexceptions -fcxx-exceptions -Wno-unevaluated-expression
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++2a %s -fexceptions -fcxx-exceptions -Wno-unevaluated-expression -fexperimental-new-constant-interpreter
+namespace std {
+struct type_info;
+}
+
void f(); // expected-note {{possible target for call}}
void f(int); // expected-note {{possible target for call}}
@@ -97,3 +101,17 @@ void j() noexcept(0);
void k() noexcept(1);
void l() noexcept(2); // expected-error {{noexcept specifier argument evaluates to 2, which cannot be narrowed to type 'bool'}}
} // namespace P1401
+
+template<bool NoexceptConstructor, bool NoexceptDestructor>
+struct Polymorphic {
+ Polymorphic() noexcept(NoexceptConstructor) {}
+ virtual ~Polymorphic() noexcept(NoexceptDestructor) {}
+};
+
+static_assert(noexcept(typeid(Polymorphic<false, false>{}))); // Not evaluated (not glvalue)
+static_assert(noexcept(typeid((Polymorphic<true, true>&&) Polymorphic<true, true>{})));
+static_assert(!noexcept(typeid((Polymorphic<false, true>&&) Polymorphic<false, true>{})));
+static_assert(!noexcept(typeid((Polymorphic<true, false>&&) Polymorphic<true, false>{})));
+static_assert(!noexcept(typeid(*&(const Polymorphic<true, true>&) Polymorphic<true, true>{})));
+static_assert(!noexcept(typeid(*&(const Polymorphic<false, true>&) Polymorphic<false, true>{})));
+static_assert(!noexcept(typeid(*&(const Polymorphic<true, false>&) Polymorphic<true, false>{})));
>From 1c6c9bf7f30d60a3a69747cd993d49908447d106 Mon Sep 17 00:00:00 2001
From: Mital Ashok <mital at mitalashok.co.uk>
Date: Tue, 18 Jun 2024 06:05:43 +0100
Subject: [PATCH 2/3] Apply suggestions from code review
Co-authored-by: Timm Baeder <tbaeder at redhat.com>
---
clang/lib/Sema/SemaExceptionSpec.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp
index ef1128cedf994..2222fcdc39532 100644
--- a/clang/lib/Sema/SemaExceptionSpec.cpp
+++ b/clang/lib/Sema/SemaExceptionSpec.cpp
@@ -1111,14 +1111,14 @@ static CanThrowResult canDynamicCastThrow(const CXXDynamicCastExpr *DC) {
}
static CanThrowResult canTypeidThrow(Sema &S, const CXXTypeidExpr *DC) {
- // Operand is not evaluated, cannot possibly throw
+ // Operand is not evaluated, cannot possibly throw.
if (!DC->isPotentiallyEvaluated())
return CT_Cannot;
if (DC->isValueDependent())
return CT_Dependent;
- // Can throw std::bad_typeid if a nullptr is dereferenced
+ // Can throw std::bad_typeid if a nullptr is dereferenced.
if (DC->hasNullCheck())
return CT_Can;
>From fb7e2debf69235e5c7960353ab497fa159e745f8 Mon Sep 17 00:00:00 2001
From: Mital Ashok <mital at mitalashok.co.uk>
Date: Tue, 18 Jun 2024 07:11:53 +0100
Subject: [PATCH 3/3] Make sure isPotentiallyEvaluated is not called on a
dependant expression (which might become potentially evaluated once types are
known)
---
clang/lib/Sema/SemaExceptionSpec.cpp | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp
index 2222fcdc39532..fb2250d1c98af 100644
--- a/clang/lib/Sema/SemaExceptionSpec.cpp
+++ b/clang/lib/Sema/SemaExceptionSpec.cpp
@@ -1111,13 +1111,17 @@ static CanThrowResult canDynamicCastThrow(const CXXDynamicCastExpr *DC) {
}
static CanThrowResult canTypeidThrow(Sema &S, const CXXTypeidExpr *DC) {
- // Operand is not evaluated, cannot possibly throw.
- if (!DC->isPotentiallyEvaluated())
+ // A typeid of a type is a constant and does not throw.
+ if (DC->isTypeOperand())
return CT_Cannot;
if (DC->isValueDependent())
return CT_Dependent;
+ // If this operand is not evaluated it cannot possibly throw.
+ if (!DC->isPotentiallyEvaluated())
+ return CT_Cannot;
+
// Can throw std::bad_typeid if a nullptr is dereferenced.
if (DC->hasNullCheck())
return CT_Can;
More information about the cfe-commits
mailing list