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 <mi...@mitalashok.co.uk>
Date: Mon, 17 Jun 2024 21:48:57 +0100
Subject: [PATCH 1/5] [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 <mi...@mitalashok.co.uk>
Date: Tue, 18 Jun 2024 06:05:43 +0100
Subject: [PATCH 2/5] Apply suggestions from code review

Co-authored-by: Timm Baeder <tbae...@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 <mi...@mitalashok.co.uk>
Date: Tue, 18 Jun 2024 07:11:53 +0100
Subject: [PATCH 3/5] 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;

>From 77b5b6477f9af79777a35cfdf1fb4659e631be71 Mon Sep 17 00:00:00 2001
From: Mital Ashok <mi...@mitalashok.co.uk>
Date: Tue, 18 Jun 2024 10:51:57 +0100
Subject: [PATCH 4/5] Add tests for noexcept of dependent typeids

---
 .../SemaCXX/cxx0x-noexcept-expression.cpp     | 37 +++++++++++++++++++
 1 file changed, 37 insertions(+)

diff --git a/clang/test/SemaCXX/cxx0x-noexcept-expression.cpp 
b/clang/test/SemaCXX/cxx0x-noexcept-expression.cpp
index 1e86a31fffcbf..a036fa6636847 100644
--- a/clang/test/SemaCXX/cxx0x-noexcept-expression.cpp
+++ b/clang/test/SemaCXX/cxx0x-noexcept-expression.cpp
@@ -102,6 +102,7 @@ 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
 
+namespace typeid_ {
 template<bool NoexceptConstructor, bool NoexceptDestructor>
 struct Polymorphic {
   Polymorphic() noexcept(NoexceptConstructor) {}
@@ -115,3 +116,39 @@ static_assert(!noexcept(typeid((Polymorphic<true, 
false>&&) Polymorphic<true, fa
 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>{})));
+
+template<bool B>
+struct X {
+  template<typename T> void f();
+};
+template<typename T>
+void f1() {
+  X<noexcept(typeid(*T{}))> dependent;
+  dependent.f<void>();
+  // expected-error@-1 {{use 'template' keyword to treat 'f' as a dependent 
template name}}
+}
+template<typename... T>
+void f2() {
+  X<noexcept(typeid(*((static_cast<Polymorphic<false, false>*>(nullptr) && ... 
&& T{}))))> dependent;
+  dependent.f<void>();
+  // expected-error@-1 {{use 'template' keyword to treat 'f' as a dependent 
template name}}
+}
+template<typename T>
+void f3() {
+  X<noexcept(typeid(*static_cast<T*>(nullptr)))> dependent;
+  dependent.f<void>();
+  // expected-error@-1 {{use 'template' keyword to treat 'f' as a dependent 
template name}}
+}
+template<typename T>
+void f4() {
+  X<noexcept(typeid(T))> not_dependent;
+  not_dependent.non_existant();
+  // expected-error@-1 {{no member named 'non_existant' in 'typeid_::X<true>'}}
+}
+template<typename T>
+void f5() {
+  X<noexcept(typeid(sizeof(sizeof(T))))> not_dependent;
+  not_dependent.non_existant();
+  // expected-error@-1 {{no member named 'non_existant' in 'typeid_::X<true>'}}
+}
+} // namespace typeid_

>From 240d6256e226a0a916be55896627319ec24167ae Mon Sep 17 00:00:00 2001
From: Mital Ashok <mi...@mitalashok.co.uk>
Date: Wed, 19 Jun 2024 17:17:21 +0100
Subject: [PATCH 5/5] Comment for dependent noexcept tests

---
 clang/test/SemaCXX/cxx0x-noexcept-expression.cpp | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/clang/test/SemaCXX/cxx0x-noexcept-expression.cpp 
b/clang/test/SemaCXX/cxx0x-noexcept-expression.cpp
index a036fa6636847..c616a77f36619 100644
--- a/clang/test/SemaCXX/cxx0x-noexcept-expression.cpp
+++ b/clang/test/SemaCXX/cxx0x-noexcept-expression.cpp
@@ -124,31 +124,36 @@ struct X {
 template<typename T>
 void f1() {
   X<noexcept(typeid(*T{}))> dependent;
-  dependent.f<void>();
+  // `dependent` should be type-dependent because the noexcept-expression 
should be value-dependent
+  // (it is true if T is int*, false if T is Polymorphic<false, false>* for 
example)
+  dependent.f<void>();  // This should need to be `.template f` to parse as a 
template
   // expected-error@-1 {{use 'template' keyword to treat 'f' as a dependent 
template name}}
 }
 template<typename... T>
 void f2() {
   X<noexcept(typeid(*((static_cast<Polymorphic<false, false>*>(nullptr) && ... 
&& T{}))))> dependent;
+  // X<true> when T...[0] is a type with some operator&& which returns int*
+  // X<false> when sizeof...(T) == 0
   dependent.f<void>();
   // expected-error@-1 {{use 'template' keyword to treat 'f' as a dependent 
template name}}
 }
 template<typename T>
 void f3() {
   X<noexcept(typeid(*static_cast<T*>(nullptr)))> dependent;
+  // X<true> when T is int, X<false> when T is Polymorphic<false, false>
   dependent.f<void>();
   // expected-error@-1 {{use 'template' keyword to treat 'f' as a dependent 
template name}}
 }
 template<typename T>
 void f4() {
   X<noexcept(typeid(T))> not_dependent;
-  not_dependent.non_existant();
-  // expected-error@-1 {{no member named 'non_existant' in 'typeid_::X<true>'}}
+  not_dependent.non_existent();
+  // expected-error@-1 {{no member named 'non_existent' in 'typeid_::X<true>'}}
 }
 template<typename T>
 void f5() {
   X<noexcept(typeid(sizeof(sizeof(T))))> not_dependent;
-  not_dependent.non_existant();
-  // expected-error@-1 {{no member named 'non_existant' in 'typeid_::X<true>'}}
+  not_dependent.non_existent();
+  // expected-error@-1 {{no member named 'non_existent' in 'typeid_::X<true>'}}
 }
 } // namespace typeid_

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to