From 84a8f3c0e53b06478a0c7574cf684a795acdb437 Mon Sep 17 00:00:00 2001 From: delimbetov <1starfall1@gmail.com> Date: Thu, 6 Jun 2024 16:08:03 +0100 Subject: [PATCH 01/12] add is_noexcept to meta header --- libcxx/include/experimental/meta | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/libcxx/include/experimental/meta b/libcxx/include/experimental/meta index 0a2be36879fe49..56a296da3225c6 100644 --- a/libcxx/include/experimental/meta +++ b/libcxx/include/experimental/meta @@ -76,6 +76,7 @@ consteval auto is_override(info) -> bool; consteval auto is_deleted(info) -> bool; consteval auto is_defaulted(info) -> bool; consteval auto is_explicit(info) -> bool; +consteval bool is_noexcept(info) -> bool; consteval auto is_bit_field(info) -> bool; consteval auto has_static_storage_duration(info) -> bool; consteval auto has_internal_linkage(info) -> bool; @@ -183,6 +184,7 @@ enum : unsigned { __metafn_is_deleted, __metafn_is_defaulted, __metafn_is_explicit, + __metafn_is_noexcept, __metafn_is_bit_field, __metafn_has_static_storage_duration, __metafn_has_internal_linkage, @@ -692,6 +694,11 @@ consteval auto is_explicit(info r) -> bool { return __metafunction(detail::__metafn_is_explicit, r); } +// Returns whether the reflected member function, it's type, closure type of a non-generic lambda or it's value is noexcept. +consteval auto is_noexcept(info r) -> bool { + return __metafunction(detail::__metafn_is_noexcept, r); +} + // Returns whether the reflected class data member is a bit field. consteval auto is_bit_field(info r) -> bool { return __metafunction(detail::__metafn_is_bit_field, r); From 56c9f7b0fe2e43962592295e40085683e4e2f52d Mon Sep 17 00:00:00 2001 From: delimbetov <1starfall1@gmail.com> Date: Thu, 6 Jun 2024 18:38:47 +0100 Subject: [PATCH 02/12] add tests for is_noexcept and stub implementation --- clang/lib/Sema/Metafunctions.cpp | 10 ++ .../reflection/member-classification.pass.cpp | 109 ++++++++++++++++++ 2 files changed, 119 insertions(+) diff --git a/clang/lib/Sema/Metafunctions.cpp b/clang/lib/Sema/Metafunctions.cpp index 55da96bf319b7a..d1d7361ebab2b6 100644 --- a/clang/lib/Sema/Metafunctions.cpp +++ b/clang/lib/Sema/Metafunctions.cpp @@ -150,6 +150,10 @@ static bool is_explicit(APValue &Result, Sema &S, EvalFn Evaluator, QualType ResultTy, SourceRange Range, ArrayRef Args); +static bool is_noexcept(APValue &Result, Sema &S, EvalFn Evaluator, + QualType ResultTy, SourceRange Range, + ArrayRef Args); + static bool is_bit_field(APValue &Result, Sema &S, EvalFn Evaluator, QualType ResultTy, SourceRange Range, ArrayRef Args); @@ -358,6 +362,7 @@ static constexpr Metafunction Metafunctions[] = { { Metafunction::MFRK_bool, 1, 1, is_deleted }, { Metafunction::MFRK_bool, 1, 1, is_defaulted }, { Metafunction::MFRK_bool, 1, 1, is_explicit }, + { Metafunction::MFRK_bool, 1, 1, is_noexcept }, { Metafunction::MFRK_bool, 1, 1, is_bit_field }, { Metafunction::MFRK_bool, 1, 1, has_static_storage_duration }, { Metafunction::MFRK_bool, 1, 1, has_internal_linkage }, @@ -2508,6 +2513,11 @@ bool is_explicit(APValue &Result, Sema &S, EvalFn Evaluator, QualType ResultTy, llvm_unreachable("invalid reflection type"); } +bool is_noexcept(APValue &Result, Sema &S, EvalFn Evaluator, QualType ResultTy, + SourceRange Range, ArrayRef Args) { + return is_explicit(Result, S, Evaluator, ResultTy, Range, Args); +} + bool is_bit_field(APValue &Result, Sema &S, EvalFn Evaluator, QualType ResultTy, SourceRange Range, ArrayRef Args) { assert(Args[0]->getType()->isReflectionType()); diff --git a/libcxx/test/std/experimental/reflection/member-classification.pass.cpp b/libcxx/test/std/experimental/reflection/member-classification.pass.cpp index c9242593c05ae5..3826768084ece4 100644 --- a/libcxx/test/std/experimental/reflection/member-classification.pass.cpp +++ b/libcxx/test/std/experimental/reflection/member-classification.pass.cpp @@ -359,6 +359,115 @@ static_assert(!is_explicit(^::)); static_assert(!is_explicit(^inner)); } // namespace explicit_functions + // ================== + // noexcept_functions + // ================== + +namespace noexcept_functions { +struct S { + // methods + void noexcept_method() noexcept; + void not_noexcept_method(); + + // virtual methods + virtual void noexcept_virtual_method() noexcept; + virtual void not_noexcept_virtual_method(); + + // template methods + template + void noexcept_template_method() noexcept; + template + void not_noexcept_template_method(); +}; + +// non generic lambdas +constexpr auto noexcept_lambda = []() noexcept {}; +constexpr auto not_noexcept_lambda = []{}; + +// generic lambdas +constexpr auto noexcept_generic_lambda = []() noexcept {}; +constexpr auto not_noexcept_generic_lambda = []() {}; + +// functions +void noexcept_function() noexcept; +void not_noexcept_function() noexcept; + +// template functions +template +void noexcept_template_function() noexcept; +template +void not_noexcept_template_function() noexcept; + +// Everything mentioned in the proposal +// (no-)noexcept member functions +static_assert(is_noexcept(^S::noexcept_method)); +static_assert(!is_noexcept(^S::not_noexcept_method)); + +// (no-)noexcept member function types +static_assert(is_noexcept(type_of(^S::noexcept_method))); +static_assert(!is_noexcept(type_of(^S::not_noexcept_method))); + +// (no-)noexcept virtual methods +static_assert(is_noexcept(^S::noexcept_virtual_method)); +static_assert(!is_noexcept(^S::not_noexcept_virtual_method)); + +// (no-)noexcept virtual method types +static_assert(is_noexcept(type_of(^S::noexcept_virtual_method))); +static_assert(!is_noexcept(type_of(^S::not_noexcept_virtual_method))); + +// (no-)noexcept lambdas +static_assert(is_noexcept(^noexcept_lambda)); +static_assert(!is_noexcept(^not_noexcept_lambda)); + +// (no-)noexcept closure types +static_assert(is_noexcept(type_of(^noexcept_lambda))); +static_assert(!is_noexcept(type_of(^not_noexcept_lambda))); + +// (no-)noexcept function +static_assert(is_noexcept(^noexcept_function)); +static_assert(!is_noexcept(^not_noexcept_function)); + +// (no-)noexcept function type +static_assert(is_noexcept(type_of(^noexcept_function))); +static_assert(!is_noexcept(type_of(^not_noexcept_function))); + +// The rest (should all be false regardless of noexcept specifier) +// (no-)noexcept template methods +static_assert(!is_noexcept(^S::noexcept_template_method)); +static_assert(!is_noexcept(^S::not_noexcept_template_method)); + +// (no-)noexcept instantiated template methods +static_assert(!is_noexcept(^S::noexcept_template_method)); +static_assert(!is_noexcept(^S::not_noexcept_template_method)); +static_assert(!is_noexcept(type_of(^S::noexcept_template_method))); +static_assert(!is_noexcept(type_of(^S::not_noexcept_template_method))); + +// (no-)noexcept generic closure types +static_assert(!is_noexcept(^noexcept_generic_lambda)); +static_assert(!is_noexcept(^not_noexcept_generic_lambda)); +static_assert(!is_noexcept(type_of(^noexcept_generic_lambda))); +static_assert(!is_noexcept(type_of(^not_noexcept_generic_lambda))); + +// (no-)noexcept template functions +static_assert(!is_noexcept(^noexcept_template_function)); +static_assert(!is_noexcept(^not_noexcept_template_function)); + +// (no-)noexcept instantiated template functions +static_assert(!is_noexcept(^noexcept_template_function)); +static_assert(!is_noexcept(^not_noexcept_template_function)); +static_assert(!is_noexcept(type_of(^noexcept_template_function))); +static_assert(!is_noexcept(type_of(^not_noexcept_template_function))); + +// Random non callable types +auto x = 1; +auto s = S(); + +static_assert(!is_noexcept(^x)); +static_assert(!is_noexcept(type_of(^x))); +static_assert(!is_noexcept(^s)); +static_assert(!is_noexcept(type_of(^s))); +} // namespace noexcept_functions + // ================ // bitfield members // ================ From ad665b500bdb19424221cd96468a50fdc18ccd69 Mon Sep 17 00:00:00 2001 From: delimbetov <1starfall1@gmail.com> Date: Fri, 7 Jun 2024 18:20:09 +0100 Subject: [PATCH 03/12] add noexcept(true/false) tests move instantiated func templates into supported section --- .../reflection/member-classification.pass.cpp | 75 ++++++++++++++----- 1 file changed, 57 insertions(+), 18 deletions(-) diff --git a/libcxx/test/std/experimental/reflection/member-classification.pass.cpp b/libcxx/test/std/experimental/reflection/member-classification.pass.cpp index 3826768084ece4..c9ed85e5ea1684 100644 --- a/libcxx/test/std/experimental/reflection/member-classification.pass.cpp +++ b/libcxx/test/std/experimental/reflection/member-classification.pass.cpp @@ -367,16 +367,25 @@ namespace noexcept_functions { struct S { // methods void noexcept_method() noexcept; + void noexcept_true_method() noexcept(true); + void noexcept_false_method() noexcept(false); void not_noexcept_method(); // virtual methods - virtual void noexcept_virtual_method() noexcept; - virtual void not_noexcept_virtual_method(); + // w/o defining it complains about vtable + virtual void noexcept_virtual_method() noexcept {} + virtual void noexcept_true_virtual_method() noexcept(true) {} + virtual void noexcept_false_virtual_method() noexcept(false) {} + virtual void not_noexcept_virtual_method() {} // template methods template void noexcept_template_method() noexcept; template + void noexcept_true_template_method() noexcept(true); + template + void noexcept_false_template_method() noexcept(false); + template void not_noexcept_template_method(); }; @@ -390,31 +399,57 @@ constexpr auto not_noexcept_generic_lambda = []() {}; // functions void noexcept_function() noexcept; -void not_noexcept_function() noexcept; +void noexcept_true_function() noexcept(true); +void noexcept_false_function() noexcept(false); +void not_noexcept_function(); // template functions template void noexcept_template_function() noexcept; template -void not_noexcept_template_function() noexcept; +void noexcept_true_template_function() noexcept(true); +template +void noexcept_false_template_function() noexcept(false); +template +void not_noexcept_template_function(); // Everything mentioned in the proposal // (no-)noexcept member functions static_assert(is_noexcept(^S::noexcept_method)); +static_assert(is_noexcept(^S::noexcept_true_method)); +static_assert(!is_noexcept(^S::noexcept_false_method)); static_assert(!is_noexcept(^S::not_noexcept_method)); // (no-)noexcept member function types static_assert(is_noexcept(type_of(^S::noexcept_method))); +static_assert(is_noexcept(type_of(^S::noexcept_true_method))); +static_assert(!is_noexcept(type_of(^S::noexcept_false_method))); static_assert(!is_noexcept(type_of(^S::not_noexcept_method))); // (no-)noexcept virtual methods static_assert(is_noexcept(^S::noexcept_virtual_method)); +static_assert(is_noexcept(^S::noexcept_true_virtual_method)); +static_assert(!is_noexcept(^S::noexcept_false_virtual_method)); static_assert(!is_noexcept(^S::not_noexcept_virtual_method)); // (no-)noexcept virtual method types static_assert(is_noexcept(type_of(^S::noexcept_virtual_method))); +static_assert(is_noexcept(type_of(^S::noexcept_true_virtual_method))); +static_assert(!is_noexcept(type_of(^S::noexcept_false_virtual_method))); static_assert(!is_noexcept(type_of(^S::not_noexcept_virtual_method))); +// (no-)noexcept instantiated template methods +static_assert(is_noexcept(^S::noexcept_template_method)); +static_assert(is_noexcept(^S::noexcept_true_template_method)); +static_assert(!is_noexcept(^S::noexcept_false_template_method)); +static_assert(!is_noexcept(^S::not_noexcept_template_method)); + +// (no-)noexcept instantiated template method types +static_assert(is_noexcept(type_of(^S::noexcept_template_method))); +static_assert(is_noexcept(type_of(^S::noexcept_true_template_method))); +static_assert(!is_noexcept(type_of(^S::noexcept_false_template_method))); +static_assert(!is_noexcept(type_of(^S::not_noexcept_template_method))); + // (no-)noexcept lambdas static_assert(is_noexcept(^noexcept_lambda)); static_assert(!is_noexcept(^not_noexcept_lambda)); @@ -425,39 +460,43 @@ static_assert(!is_noexcept(type_of(^not_noexcept_lambda))); // (no-)noexcept function static_assert(is_noexcept(^noexcept_function)); +static_assert(is_noexcept(^noexcept_true_function)); +static_assert(!is_noexcept(^noexcept_false_function)); static_assert(!is_noexcept(^not_noexcept_function)); // (no-)noexcept function type static_assert(is_noexcept(type_of(^noexcept_function))); +static_assert(is_noexcept(type_of(^noexcept_true_function))); +static_assert(!is_noexcept(type_of(^noexcept_false_function))); static_assert(!is_noexcept(type_of(^not_noexcept_function))); +// (no-)noexcept instantiated template functions +static_assert(is_noexcept(^noexcept_template_function)); +static_assert(is_noexcept(^noexcept_true_template_function)); +static_assert(!is_noexcept(^noexcept_false_template_function)); +static_assert(!is_noexcept(^not_noexcept_template_function)); + +// (no-)noexcept instantiated template function types +static_assert(is_noexcept(type_of(^noexcept_template_function))); +static_assert(is_noexcept(type_of(^noexcept_true_template_function))); +static_assert(!is_noexcept(type_of(^noexcept_false_template_function))); +static_assert(!is_noexcept(type_of(^not_noexcept_template_function))); + // The rest (should all be false regardless of noexcept specifier) -// (no-)noexcept template methods +// (no-)noexcept non-instantiated template methods static_assert(!is_noexcept(^S::noexcept_template_method)); static_assert(!is_noexcept(^S::not_noexcept_template_method)); -// (no-)noexcept instantiated template methods -static_assert(!is_noexcept(^S::noexcept_template_method)); -static_assert(!is_noexcept(^S::not_noexcept_template_method)); -static_assert(!is_noexcept(type_of(^S::noexcept_template_method))); -static_assert(!is_noexcept(type_of(^S::not_noexcept_template_method))); - // (no-)noexcept generic closure types static_assert(!is_noexcept(^noexcept_generic_lambda)); static_assert(!is_noexcept(^not_noexcept_generic_lambda)); static_assert(!is_noexcept(type_of(^noexcept_generic_lambda))); static_assert(!is_noexcept(type_of(^not_noexcept_generic_lambda))); -// (no-)noexcept template functions +// (no-)noexcept non-instantiated template functions static_assert(!is_noexcept(^noexcept_template_function)); static_assert(!is_noexcept(^not_noexcept_template_function)); -// (no-)noexcept instantiated template functions -static_assert(!is_noexcept(^noexcept_template_function)); -static_assert(!is_noexcept(^not_noexcept_template_function)); -static_assert(!is_noexcept(type_of(^noexcept_template_function))); -static_assert(!is_noexcept(type_of(^not_noexcept_template_function))); - // Random non callable types auto x = 1; auto s = S(); From d44dd7f7b7b6e879162a3d15eb9030fc7f61a719 Mon Sep 17 00:00:00 2001 From: delimbetov <1starfall1@gmail.com> Date: Fri, 7 Jun 2024 18:29:35 +0100 Subject: [PATCH 04/12] implement is_noexcept meta function --- clang/lib/Sema/Metafunctions.cpp | 60 +++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/clang/lib/Sema/Metafunctions.cpp b/clang/lib/Sema/Metafunctions.cpp index d1d7361ebab2b6..3b311597e8aa23 100644 --- a/clang/lib/Sema/Metafunctions.cpp +++ b/clang/lib/Sema/Metafunctions.cpp @@ -1011,6 +1011,37 @@ bool isAccessible(Sema &S, DeclContext *AccessDC, NamedDecl *D) { return Result; } +template +static bool isFunctionDeclNoexcept(const T *FuncD) { + switch (FuncD->getExceptionSpecType()) { + case EST_BasicNoexcept: + case EST_NoexceptTrue: + return true; + default: + return false; + } +} + +static bool isFunctionOrLambdaNoexcept(const QualType QT) { + const Type* T = QT.getTypePtr(); + + if (T->isFunctionProtoType()) { + // This covers (virtual) methods & functions + const auto *FPT = T->getAs(); + + return isFunctionDeclNoexcept(FPT); + } else if (T->isRecordType()) { + // This branch is for lambdas only + const auto RT = T->getAs(); + const auto RecordD = cast(RT->getDecl()); + + if (RecordD && RecordD->isLambda() && !RecordD->isGenericLambda()) + return isFunctionDeclNoexcept(RecordD->getLambdaCallOperator()); + } + + return false; +} + // ----------------------------------------------------------------------------- // Metafunction implementations // ----------------------------------------------------------------------------- @@ -2515,7 +2546,34 @@ bool is_explicit(APValue &Result, Sema &S, EvalFn Evaluator, QualType ResultTy, bool is_noexcept(APValue &Result, Sema &S, EvalFn Evaluator, QualType ResultTy, SourceRange Range, ArrayRef Args) { - return is_explicit(Result, S, Evaluator, ResultTy, Range, Args); + assert(Args[0]->getType()->isReflectionType()); + assert(ResultTy == S.Context.BoolTy); + + APValue R; + if (!Evaluator(R, Args[0], true)) + return true; + + switch (R.getReflection().getKind()) { + case ReflectionValue::RK_const_value: + case ReflectionValue::RK_namespace: + case ReflectionValue::RK_base_specifier: + case ReflectionValue::RK_data_member_spec: + case ReflectionValue::RK_template: + return SetAndSucceed(Result, makeBool(S.Context, false)); + case ReflectionValue::RK_type: { + const QualType QT = R.getReflectedType(); + const auto result = isFunctionOrLambdaNoexcept(QT); + + return SetAndSucceed(Result, makeBool(S.Context, result)); + } + case ReflectionValue::RK_declaration: { + const ValueDecl *D = R.getReflectedDecl(); + const auto result = isFunctionOrLambdaNoexcept(D->getType()); + + return SetAndSucceed(Result, makeBool(S.Context, result)); + } + } + llvm_unreachable("invalid reflection type"); } bool is_bit_field(APValue &Result, Sema &S, EvalFn Evaluator, QualType ResultTy, From 1aa2ccc3061ec24de0853a58c95b13115c1592d8 Mon Sep 17 00:00:00 2001 From: Delimbetov Kirill <1starfall1@gmail.com> Date: Mon, 10 Jun 2024 13:24:31 +0100 Subject: [PATCH 05/12] Update libcxx/include/experimental/meta Co-authored-by: Daniel M. Katz --- libcxx/include/experimental/meta | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libcxx/include/experimental/meta b/libcxx/include/experimental/meta index 56a296da3225c6..fd925ff8a0b2b3 100644 --- a/libcxx/include/experimental/meta +++ b/libcxx/include/experimental/meta @@ -694,7 +694,8 @@ consteval auto is_explicit(info r) -> bool { return __metafunction(detail::__metafn_is_explicit, r); } -// Returns whether the reflected member function, it's type, closure type of a non-generic lambda or it's value is noexcept. +// Returns whether the reflected function, function pointer, function type, +// non-generic lambda expression, or non-generic closure type is noexcept. consteval auto is_noexcept(info r) -> bool { return __metafunction(detail::__metafn_is_noexcept, r); } From f36f7375dc2458d101a1d8b02c0844dab18b7736 Mon Sep 17 00:00:00 2001 From: delimbetov <1starfall1@gmail.com> Date: Mon, 10 Jun 2024 22:16:52 +0100 Subject: [PATCH 06/12] CR: make isFunctionDeclNoexcept a non-generic lambda instead of a template function make switch ident follow the style of this file --- clang/lib/Sema/Metafunctions.cpp | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/clang/lib/Sema/Metafunctions.cpp b/clang/lib/Sema/Metafunctions.cpp index 3b311597e8aa23..abac34ec020730 100644 --- a/clang/lib/Sema/Metafunctions.cpp +++ b/clang/lib/Sema/Metafunctions.cpp @@ -1011,32 +1011,34 @@ bool isAccessible(Sema &S, DeclContext *AccessDC, NamedDecl *D) { return Result; } -template -static bool isFunctionDeclNoexcept(const T *FuncD) { - switch (FuncD->getExceptionSpecType()) { +static bool isFunctionOrLambdaNoexcept(const QualType QT) { + constexpr auto isExceptionSpecNoexcept = []( + const ExceptionSpecificationType EST) { + switch (EST) { case EST_BasicNoexcept: case EST_NoexceptTrue: return true; default: return false; - } -} + } + }; -static bool isFunctionOrLambdaNoexcept(const QualType QT) { const Type* T = QT.getTypePtr(); if (T->isFunctionProtoType()) { // This covers (virtual) methods & functions const auto *FPT = T->getAs(); - return isFunctionDeclNoexcept(FPT); + return isExceptionSpecNoexcept(FPT->getExceptionSpecType()); } else if (T->isRecordType()) { // This branch is for lambdas only const auto RT = T->getAs(); const auto RecordD = cast(RT->getDecl()); - if (RecordD && RecordD->isLambda() && !RecordD->isGenericLambda()) - return isFunctionDeclNoexcept(RecordD->getLambdaCallOperator()); + if (RecordD && RecordD->isLambda() && !RecordD->isGenericLambda()) { + const auto EST = RecordD->getLambdaCallOperator()->getExceptionSpecType(); + return isExceptionSpecNoexcept(EST); + } } return false; From 2e8d44402dfd565db665a0a1674e187a9465231f Mon Sep 17 00:00:00 2001 From: delimbetov <1starfall1@gmail.com> Date: Thu, 13 Jun 2024 22:10:22 +0100 Subject: [PATCH 07/12] support changes in ReflectionValue enum --- clang/lib/Sema/Metafunctions.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/clang/lib/Sema/Metafunctions.cpp b/clang/lib/Sema/Metafunctions.cpp index ff6e719505e2d9..2a965d0430f0a3 100644 --- a/clang/lib/Sema/Metafunctions.cpp +++ b/clang/lib/Sema/Metafunctions.cpp @@ -2564,11 +2564,12 @@ bool is_noexcept(APValue &Result, Sema &S, EvalFn Evaluator, QualType ResultTy, return true; switch (R.getReflection().getKind()) { - case ReflectionValue::RK_const_value: + case ReflectionValue::RK_null: + case ReflectionValue::RK_expr_result: + case ReflectionValue::RK_template: case ReflectionValue::RK_namespace: case ReflectionValue::RK_base_specifier: case ReflectionValue::RK_data_member_spec: - case ReflectionValue::RK_template: return SetAndSucceed(Result, makeBool(S.Context, false)); case ReflectionValue::RK_type: { const QualType QT = R.getReflectedType(); From 4c8e8bad9bae7946f879fba5ffbf78bef45b294f Mon Sep 17 00:00:00 2001 From: delimbetov <1starfall1@gmail.com> Date: Thu, 13 Jun 2024 22:10:38 +0100 Subject: [PATCH 08/12] more tests for is_noexcept --- .../reflection/member-classification.pass.cpp | 68 ++++++++++++++++--- 1 file changed, 60 insertions(+), 8 deletions(-) diff --git a/libcxx/test/std/experimental/reflection/member-classification.pass.cpp b/libcxx/test/std/experimental/reflection/member-classification.pass.cpp index c9ed85e5ea1684..21ce53fb29de9c 100644 --- a/libcxx/test/std/experimental/reflection/member-classification.pass.cpp +++ b/libcxx/test/std/experimental/reflection/member-classification.pass.cpp @@ -497,14 +497,66 @@ static_assert(!is_noexcept(type_of(^not_noexcept_generic_lambda))); static_assert(!is_noexcept(^noexcept_template_function)); static_assert(!is_noexcept(^not_noexcept_template_function)); -// Random non callable types -auto x = 1; -auto s = S(); - -static_assert(!is_noexcept(^x)); -static_assert(!is_noexcept(type_of(^x))); -static_assert(!is_noexcept(^s)); -static_assert(!is_noexcept(type_of(^s))); +// Expressions that can't be noexcept +// Namespaces +static_assert(!is_noexcept(^::)); +static_assert(!is_noexcept(^noexcept_functions)); + +// Non callable id-expressions & their types +struct T { + static const int static_mem = 1; + int non_static_mem = 2; +}; + +template +struct TT {}; + +enum class EC { + Something +}; + +enum E { + E_Something +}; + +static auto static_x = 1; +auto non_static_x = static_x; +auto t = T(); +auto template_t = TT(); +int c_array[] = {1, 2}; +auto [structured_binding1, structured_binding2] = c_array; + +// a variable +static_assert(!is_noexcept(^static_x)); +static_assert(!is_noexcept(type_of(^static_x))); +static_assert(!is_noexcept(^non_static_x)); +static_assert(!is_noexcept(type_of(^non_static_x))); + +// a static data member +static_assert(!is_noexcept(^T::static_mem)); +static_assert(!is_noexcept(type_of(^T::static_mem))); + +// a structured binding +static_assert(!is_noexcept(^structured_binding1)); +static_assert(!is_noexcept(type_of(^structured_binding1))); + +// a non static data member +static_assert(!is_noexcept(^t.non_static_mem)); +static_assert(!is_noexcept(type_of(^t.non_static_mem))); + +// a template +static_assert(!is_noexcept(^TT)); +static_assert(!is_noexcept(^template_t)); +static_assert(!is_noexcept(type_of(^template_t))); + +// an enum +static_assert(!is_noexcept(^EC)); +static_assert(!is_noexcept(^EC::Something)); +static_assert(!is_noexcept(type_of(^EC::Something))); + +static_assert(!is_noexcept(^E)); +static_assert(!is_noexcept(^E_Something)); +static_assert(!is_noexcept(type_of(^E_Something))); } // namespace noexcept_functions // ================ From 3f5fc80dd8009ee50073dd7e43369bf9a75444f9 Mon Sep 17 00:00:00 2001 From: delimbetov <1starfall1@gmail.com> Date: Fri, 21 Jun 2024 17:40:02 +0100 Subject: [PATCH 09/12] support function pointers & change the way member variable is reflected --- clang/lib/Sema/Metafunctions.cpp | 18 +++- .../reflection/member-classification.pass.cpp | 99 ++++++++++++++++++- 2 files changed, 112 insertions(+), 5 deletions(-) diff --git a/clang/lib/Sema/Metafunctions.cpp b/clang/lib/Sema/Metafunctions.cpp index 0c9d6870038b8a..8261806dc019ff 100644 --- a/clang/lib/Sema/Metafunctions.cpp +++ b/clang/lib/Sema/Metafunctions.cpp @@ -1104,6 +1104,15 @@ bool isAccessible(Sema &S, DeclContext *AccessDC, NamedDecl *D) { return Result; } +static auto extractPointeeTypeForFunctionsAndMethods(const QualType QT) { + const Type* T = QT.getTypePtr(); + + if (T->isFunctionPointerType() || T->isMemberFunctionPointerType()) + return T->getPointeeType().getTypePtr(); + else + return T; +} + static bool isFunctionOrLambdaNoexcept(const QualType QT) { constexpr auto isExceptionSpecNoexcept = []( const ExceptionSpecificationType EST) { @@ -1116,7 +1125,7 @@ static bool isFunctionOrLambdaNoexcept(const QualType QT) { } }; - const Type* T = QT.getTypePtr(); + const Type* T = extractPointeeTypeForFunctionsAndMethods(QT); if (T->isFunctionProtoType()) { // This covers (virtual) methods & functions @@ -2678,12 +2687,17 @@ bool is_noexcept(APValue &Result, Sema &S, EvalFn Evaluator, QualType ResultTy, switch (R.getReflection().getKind()) { case ReflectionValue::RK_null: - case ReflectionValue::RK_expr_result: case ReflectionValue::RK_template: case ReflectionValue::RK_namespace: case ReflectionValue::RK_base_specifier: case ReflectionValue::RK_data_member_spec: return SetAndSucceed(Result, makeBool(S.Context, false)); + case ReflectionValue::RK_expr_result: { + const auto ER = R.getReflectedExprResult(); + const auto result = isFunctionOrLambdaNoexcept(ER->getType()); + + return SetAndSucceed(Result, makeBool(S.Context, result)); + } case ReflectionValue::RK_type: { const QualType QT = R.getReflectedType(); const auto result = isFunctionOrLambdaNoexcept(QT); diff --git a/libcxx/test/std/experimental/reflection/member-classification.pass.cpp b/libcxx/test/std/experimental/reflection/member-classification.pass.cpp index 4a92aa4bcce52c..176606b13fabe5 100644 --- a/libcxx/test/std/experimental/reflection/member-classification.pass.cpp +++ b/libcxx/test/std/experimental/reflection/member-classification.pass.cpp @@ -426,7 +426,24 @@ static_assert(is_noexcept(type_of(^S::noexcept_true_method))); static_assert(!is_noexcept(type_of(^S::noexcept_false_method))); static_assert(!is_noexcept(type_of(^S::not_noexcept_method))); -// (no-)noexcept virtual methods +// (no-)noexcept member function pointers +static_assert(is_noexcept(std::meta::reflect_value(&S::noexcept_method))); +static_assert(is_noexcept(std::meta::reflect_value(&S::noexcept_true_method))); +static_assert( + !is_noexcept(std::meta::reflect_value(&S::noexcept_false_method))); +static_assert(!is_noexcept(std::meta::reflect_value(&S::not_noexcept_method))); + +// (no-)noexcept member function pointer types +static_assert( + is_noexcept(type_of(std::meta::reflect_value(&S::noexcept_method)))); +static_assert( + is_noexcept(type_of(std::meta::reflect_value(&S::noexcept_true_method)))); +static_assert( + !is_noexcept(type_of(std::meta::reflect_value(&S::noexcept_false_method)))); +static_assert( + !is_noexcept(type_of(std::meta::reflect_value(&S::not_noexcept_method)))); + +// (no-)noexcept virtual method static_assert(is_noexcept(^S::noexcept_virtual_method)); static_assert(is_noexcept(^S::noexcept_true_virtual_method)); static_assert(!is_noexcept(^S::noexcept_false_virtual_method)); @@ -438,6 +455,26 @@ static_assert(is_noexcept(type_of(^S::noexcept_true_virtual_method))); static_assert(!is_noexcept(type_of(^S::noexcept_false_virtual_method))); static_assert(!is_noexcept(type_of(^S::not_noexcept_virtual_method))); +// (no-)noexcept virtual method pointers +static_assert( + is_noexcept(std::meta::reflect_value(&S::noexcept_virtual_method))); +static_assert( + is_noexcept(std::meta::reflect_value(&S::noexcept_true_virtual_method))); +static_assert( + !is_noexcept(std::meta::reflect_value(&S::noexcept_false_virtual_method))); +static_assert( + !is_noexcept(std::meta::reflect_value(&S::not_noexcept_virtual_method))); + +// (no-)noexcept virtual method pointer types +static_assert(is_noexcept( + type_of(std::meta::reflect_value(&S::noexcept_virtual_method)))); +static_assert(is_noexcept( + type_of(std::meta::reflect_value(&S::noexcept_true_virtual_method)))); +static_assert(!is_noexcept( + type_of(std::meta::reflect_value(&S::noexcept_false_virtual_method)))); +static_assert(!is_noexcept( + type_of(std::meta::reflect_value(&S::not_noexcept_virtual_method)))); + // (no-)noexcept instantiated template methods static_assert(is_noexcept(^S::noexcept_template_method)); static_assert(is_noexcept(^S::noexcept_true_template_method)); @@ -450,6 +487,26 @@ static_assert(is_noexcept(type_of(^S::noexcept_true_template_method))); static_assert(!is_noexcept(type_of(^S::noexcept_false_template_method))); static_assert(!is_noexcept(type_of(^S::not_noexcept_template_method))); +// (no-)noexcept instantiated template method pointers +static_assert(is_noexcept( + std::meta::reflect_value(&S::noexcept_template_method))); +static_assert(is_noexcept( + std::meta::reflect_value(&S::noexcept_true_template_method))); +static_assert(!is_noexcept( + std::meta::reflect_value(&S::noexcept_false_template_method))); +static_assert(!is_noexcept( + std::meta::reflect_value(&S::not_noexcept_template_method))); + +// (no-)noexcept instantiated template method pointer types +static_assert(is_noexcept( + type_of(std::meta::reflect_value(&S::noexcept_template_method)))); +static_assert(is_noexcept( + type_of(std::meta::reflect_value(&S::noexcept_true_template_method)))); +static_assert(!is_noexcept( + type_of(std::meta::reflect_value(&S::noexcept_false_template_method)))); +static_assert(!is_noexcept( + type_of(std::meta::reflect_value(&S::not_noexcept_template_method)))); + // (no-)noexcept lambdas static_assert(is_noexcept(^noexcept_lambda)); static_assert(!is_noexcept(^not_noexcept_lambda)); @@ -470,6 +527,22 @@ static_assert(is_noexcept(type_of(^noexcept_true_function))); static_assert(!is_noexcept(type_of(^noexcept_false_function))); static_assert(!is_noexcept(type_of(^not_noexcept_function))); +// (no-)noexcept function pointer +static_assert(is_noexcept(^noexcept_function)); +static_assert(is_noexcept(^noexcept_true_function)); +static_assert(!is_noexcept(^noexcept_false_function)); +static_assert(!is_noexcept(^not_noexcept_function)); + +// (no-)noexcept function pointer type +static_assert( + is_noexcept(type_of(std::meta::reflect_value(&noexcept_function)))); +static_assert( + is_noexcept(type_of(std::meta::reflect_value(&noexcept_true_function)))); +static_assert( + !is_noexcept(type_of(std::meta::reflect_value(&noexcept_false_function)))); +static_assert( + !is_noexcept(type_of(std::meta::reflect_value(¬_noexcept_function)))); + // (no-)noexcept instantiated template functions static_assert(is_noexcept(^noexcept_template_function)); static_assert(is_noexcept(^noexcept_true_template_function)); @@ -482,6 +555,26 @@ static_assert(is_noexcept(type_of(^noexcept_true_template_function))); static_assert(!is_noexcept(type_of(^noexcept_false_template_function))); static_assert(!is_noexcept(type_of(^not_noexcept_template_function))); +// (no-)noexcept instantiated template function pointers +static_assert( + is_noexcept(std::meta::reflect_value(&noexcept_template_function))); +static_assert( + is_noexcept(std::meta::reflect_value(&noexcept_true_template_function))); +static_assert(!is_noexcept( + std::meta::reflect_value(&noexcept_false_template_function))); +static_assert( + !is_noexcept(std::meta::reflect_value(¬_noexcept_template_function))); + +// (no-)noexcept instantiated template function pointer types +static_assert(is_noexcept( + type_of(std::meta::reflect_value(&noexcept_template_function)))); +static_assert(is_noexcept( + type_of(std::meta::reflect_value(&noexcept_true_template_function)))); +static_assert(!is_noexcept( + type_of(std::meta::reflect_value(&noexcept_false_template_function)))); +static_assert(!is_noexcept( + type_of(std::meta::reflect_value(¬_noexcept_template_function)))); + // The rest (should all be false regardless of noexcept specifier) // (no-)noexcept non-instantiated template methods static_assert(!is_noexcept(^S::noexcept_template_method)); @@ -541,8 +634,8 @@ static_assert(!is_noexcept(^structured_binding1)); static_assert(!is_noexcept(type_of(^structured_binding1))); // a non static data member -static_assert(!is_noexcept(^t.non_static_mem)); -static_assert(!is_noexcept(type_of(^t.non_static_mem))); +static_assert(!is_noexcept(^T::non_static_mem)); +static_assert(!is_noexcept(type_of(^T::non_static_mem))); // a template static_assert(!is_noexcept(^TT)); From dd914d14f5e408aaab468221125f361c43fe120e Mon Sep 17 00:00:00 2001 From: delimbetov <1starfall1@gmail.com> Date: Mon, 1 Jul 2024 18:19:11 +0100 Subject: [PATCH 10/12] remove support of lambdas and func pointers to conform to r5 --- clang/lib/Sema/Metafunctions.cpp | 42 +---- .../reflection/member-classification.pass.cpp | 148 +++++++++--------- 2 files changed, 81 insertions(+), 109 deletions(-) diff --git a/clang/lib/Sema/Metafunctions.cpp b/clang/lib/Sema/Metafunctions.cpp index 4cbda9104e35f3..085477a996a16f 100644 --- a/clang/lib/Sema/Metafunctions.cpp +++ b/clang/lib/Sema/Metafunctions.cpp @@ -1108,43 +1108,20 @@ bool isAccessible(Sema &S, DeclContext *AccessDC, NamedDecl *D) { return Result; } -static auto extractPointeeTypeForFunctionsAndMethods(const QualType QT) { +static bool isFunctionOrLambdaNoexcept(const QualType QT) { const Type* T = QT.getTypePtr(); - - if (T->isFunctionPointerType() || T->isMemberFunctionPointerType()) - return T->getPointeeType().getTypePtr(); - else - return T; -} -static bool isFunctionOrLambdaNoexcept(const QualType QT) { - constexpr auto isExceptionSpecNoexcept = []( - const ExceptionSpecificationType EST) { - switch (EST) { + if (T->isFunctionProtoType()) { + // This covers (virtual) methods & functions + const auto *FPT = T->getAs(); + + switch (FPT->getExceptionSpecType()) { case EST_BasicNoexcept: case EST_NoexceptTrue: return true; default: return false; } - }; - - const Type* T = extractPointeeTypeForFunctionsAndMethods(QT); - - if (T->isFunctionProtoType()) { - // This covers (virtual) methods & functions - const auto *FPT = T->getAs(); - - return isExceptionSpecNoexcept(FPT->getExceptionSpecType()); - } else if (T->isRecordType()) { - // This branch is for lambdas only - const auto RT = T->getAs(); - const auto RecordD = cast(RT->getDecl()); - - if (RecordD && RecordD->isLambda() && !RecordD->isGenericLambda()) { - const auto EST = RecordD->getLambdaCallOperator()->getExceptionSpecType(); - return isExceptionSpecNoexcept(EST); - } } return false; @@ -2703,17 +2680,12 @@ bool is_noexcept(APValue &Result, Sema &S, EvalFn Evaluator, QualType ResultTy, switch (R.getReflection().getKind()) { case ReflectionValue::RK_null: + case ReflectionValue::RK_expr_result: case ReflectionValue::RK_template: case ReflectionValue::RK_namespace: case ReflectionValue::RK_base_specifier: case ReflectionValue::RK_data_member_spec: return SetAndSucceed(Result, makeBool(S.Context, false)); - case ReflectionValue::RK_expr_result: { - const auto ER = R.getReflectedExprResult(); - const auto result = isFunctionOrLambdaNoexcept(ER->getType()); - - return SetAndSucceed(Result, makeBool(S.Context, result)); - } case ReflectionValue::RK_type: { const QualType QT = R.getReflectedType(); const auto result = isFunctionOrLambdaNoexcept(QT); diff --git a/libcxx/test/std/experimental/reflection/member-classification.pass.cpp b/libcxx/test/std/experimental/reflection/member-classification.pass.cpp index f9aa4fb02fcff1..376f4ac44168bb 100644 --- a/libcxx/test/std/experimental/reflection/member-classification.pass.cpp +++ b/libcxx/test/std/experimental/reflection/member-classification.pass.cpp @@ -457,71 +457,96 @@ static_assert(is_noexcept(type_of(^S::noexcept_true_method))); static_assert(!is_noexcept(type_of(^S::noexcept_false_method))); static_assert(!is_noexcept(type_of(^S::not_noexcept_method))); +// (no-)noexcept virtual method +static_assert(is_noexcept(^S::noexcept_virtual_method)); +static_assert(is_noexcept(^S::noexcept_true_virtual_method)); +static_assert(!is_noexcept(^S::noexcept_false_virtual_method)); +static_assert(!is_noexcept(^S::not_noexcept_virtual_method)); + +// (no-)noexcept virtual method types +static_assert(is_noexcept(type_of(^S::noexcept_virtual_method))); +static_assert(is_noexcept(type_of(^S::noexcept_true_virtual_method))); +static_assert(!is_noexcept(type_of(^S::noexcept_false_virtual_method))); +static_assert(!is_noexcept(type_of(^S::not_noexcept_virtual_method))); + +// (no-)noexcept instantiated template methods +static_assert(is_noexcept(^S::noexcept_template_method)); +static_assert(is_noexcept(^S::noexcept_true_template_method)); +static_assert(!is_noexcept(^S::noexcept_false_template_method)); +static_assert(!is_noexcept(^S::not_noexcept_template_method)); + +// (no-)noexcept instantiated template method types +static_assert(is_noexcept(type_of(^S::noexcept_template_method))); +static_assert(is_noexcept(type_of(^S::noexcept_true_template_method))); +static_assert(!is_noexcept(type_of(^S::noexcept_false_template_method))); +static_assert(!is_noexcept(type_of(^S::not_noexcept_template_method))); + +// (no-)noexcept function +static_assert(is_noexcept(^noexcept_function)); +static_assert(is_noexcept(^noexcept_true_function)); +static_assert(!is_noexcept(^noexcept_false_function)); +static_assert(!is_noexcept(^not_noexcept_function)); + +// (no-)noexcept function type +static_assert(is_noexcept(type_of(^noexcept_function))); +static_assert(is_noexcept(type_of(^noexcept_true_function))); +static_assert(!is_noexcept(type_of(^noexcept_false_function))); +static_assert(!is_noexcept(type_of(^not_noexcept_function))); + +// (no-)noexcept instantiated template functions +static_assert(is_noexcept(^noexcept_template_function)); +static_assert(is_noexcept(^noexcept_true_template_function)); +static_assert(!is_noexcept(^noexcept_false_template_function)); +static_assert(!is_noexcept(^not_noexcept_template_function)); + +// (no-)noexcept instantiated template function types +static_assert(is_noexcept(type_of(^noexcept_template_function))); +static_assert(is_noexcept(type_of(^noexcept_true_template_function))); +static_assert(!is_noexcept(type_of(^noexcept_false_template_function))); +static_assert(!is_noexcept(type_of(^not_noexcept_template_function))); + +// The rest (should all be false regardless of noexcept specifier) // (no-)noexcept member function pointers -static_assert(is_noexcept(std::meta::reflect_value(&S::noexcept_method))); -static_assert(is_noexcept(std::meta::reflect_value(&S::noexcept_true_method))); +static_assert(!is_noexcept(std::meta::reflect_value(&S::noexcept_method))); +static_assert(!is_noexcept(std::meta::reflect_value(&S::noexcept_true_method))); static_assert( !is_noexcept(std::meta::reflect_value(&S::noexcept_false_method))); static_assert(!is_noexcept(std::meta::reflect_value(&S::not_noexcept_method))); // (no-)noexcept member function pointer types static_assert( - is_noexcept(type_of(std::meta::reflect_value(&S::noexcept_method)))); + !is_noexcept(type_of(std::meta::reflect_value(&S::noexcept_method)))); static_assert( - is_noexcept(type_of(std::meta::reflect_value(&S::noexcept_true_method)))); + !is_noexcept(type_of(std::meta::reflect_value(&S::noexcept_true_method)))); static_assert( !is_noexcept(type_of(std::meta::reflect_value(&S::noexcept_false_method)))); static_assert( !is_noexcept(type_of(std::meta::reflect_value(&S::not_noexcept_method)))); -// (no-)noexcept virtual method -static_assert(is_noexcept(^S::noexcept_virtual_method)); -static_assert(is_noexcept(^S::noexcept_true_virtual_method)); -static_assert(!is_noexcept(^S::noexcept_false_virtual_method)); -static_assert(!is_noexcept(^S::not_noexcept_virtual_method)); - -// (no-)noexcept virtual method types -static_assert(is_noexcept(type_of(^S::noexcept_virtual_method))); -static_assert(is_noexcept(type_of(^S::noexcept_true_virtual_method))); -static_assert(!is_noexcept(type_of(^S::noexcept_false_virtual_method))); -static_assert(!is_noexcept(type_of(^S::not_noexcept_virtual_method))); - // (no-)noexcept virtual method pointers static_assert( - is_noexcept(std::meta::reflect_value(&S::noexcept_virtual_method))); + !is_noexcept(std::meta::reflect_value(&S::noexcept_virtual_method))); static_assert( - is_noexcept(std::meta::reflect_value(&S::noexcept_true_virtual_method))); + !is_noexcept(std::meta::reflect_value(&S::noexcept_true_virtual_method))); static_assert( !is_noexcept(std::meta::reflect_value(&S::noexcept_false_virtual_method))); static_assert( !is_noexcept(std::meta::reflect_value(&S::not_noexcept_virtual_method))); // (no-)noexcept virtual method pointer types -static_assert(is_noexcept( +static_assert(!is_noexcept( type_of(std::meta::reflect_value(&S::noexcept_virtual_method)))); -static_assert(is_noexcept( +static_assert(!is_noexcept( type_of(std::meta::reflect_value(&S::noexcept_true_virtual_method)))); static_assert(!is_noexcept( type_of(std::meta::reflect_value(&S::noexcept_false_virtual_method)))); static_assert(!is_noexcept( type_of(std::meta::reflect_value(&S::not_noexcept_virtual_method)))); -// (no-)noexcept instantiated template methods -static_assert(is_noexcept(^S::noexcept_template_method)); -static_assert(is_noexcept(^S::noexcept_true_template_method)); -static_assert(!is_noexcept(^S::noexcept_false_template_method)); -static_assert(!is_noexcept(^S::not_noexcept_template_method)); - -// (no-)noexcept instantiated template method types -static_assert(is_noexcept(type_of(^S::noexcept_template_method))); -static_assert(is_noexcept(type_of(^S::noexcept_true_template_method))); -static_assert(!is_noexcept(type_of(^S::noexcept_false_template_method))); -static_assert(!is_noexcept(type_of(^S::not_noexcept_template_method))); - // (no-)noexcept instantiated template method pointers -static_assert(is_noexcept( +static_assert(!is_noexcept( std::meta::reflect_value(&S::noexcept_template_method))); -static_assert(is_noexcept( +static_assert(!is_noexcept( std::meta::reflect_value(&S::noexcept_true_template_method))); static_assert(!is_noexcept( std::meta::reflect_value(&S::noexcept_false_template_method))); @@ -529,9 +554,9 @@ static_assert(!is_noexcept( std::meta::reflect_value(&S::not_noexcept_template_method))); // (no-)noexcept instantiated template method pointer types -static_assert(is_noexcept( +static_assert(!is_noexcept( type_of(std::meta::reflect_value(&S::noexcept_template_method)))); -static_assert(is_noexcept( +static_assert(!is_noexcept( type_of(std::meta::reflect_value(&S::noexcept_true_template_method)))); static_assert(!is_noexcept( type_of(std::meta::reflect_value(&S::noexcept_false_template_method)))); @@ -539,74 +564,49 @@ static_assert(!is_noexcept( type_of(std::meta::reflect_value(&S::not_noexcept_template_method)))); // (no-)noexcept lambdas -static_assert(is_noexcept(^noexcept_lambda)); +static_assert(!is_noexcept(^noexcept_lambda)); static_assert(!is_noexcept(^not_noexcept_lambda)); // (no-)noexcept closure types -static_assert(is_noexcept(type_of(^noexcept_lambda))); +static_assert(!is_noexcept(type_of(^noexcept_lambda))); static_assert(!is_noexcept(type_of(^not_noexcept_lambda))); -// (no-)noexcept function -static_assert(is_noexcept(^noexcept_function)); -static_assert(is_noexcept(^noexcept_true_function)); -static_assert(!is_noexcept(^noexcept_false_function)); -static_assert(!is_noexcept(^not_noexcept_function)); - -// (no-)noexcept function type -static_assert(is_noexcept(type_of(^noexcept_function))); -static_assert(is_noexcept(type_of(^noexcept_true_function))); -static_assert(!is_noexcept(type_of(^noexcept_false_function))); -static_assert(!is_noexcept(type_of(^not_noexcept_function))); - // (no-)noexcept function pointer -static_assert(is_noexcept(^noexcept_function)); -static_assert(is_noexcept(^noexcept_true_function)); -static_assert(!is_noexcept(^noexcept_false_function)); -static_assert(!is_noexcept(^not_noexcept_function)); +static_assert(!is_noexcept(std::meta::reflect_value(&noexcept_function))); +static_assert(!is_noexcept(std::meta::reflect_value(&noexcept_true_function))); +static_assert(!is_noexcept(std::meta::reflect_value(&noexcept_false_function))); +static_assert(!is_noexcept(std::meta::reflect_value(¬_noexcept_function))); // (no-)noexcept function pointer type static_assert( - is_noexcept(type_of(std::meta::reflect_value(&noexcept_function)))); + !is_noexcept(type_of(std::meta::reflect_value(&noexcept_function)))); static_assert( - is_noexcept(type_of(std::meta::reflect_value(&noexcept_true_function)))); + !is_noexcept(type_of(std::meta::reflect_value(&noexcept_true_function)))); static_assert( !is_noexcept(type_of(std::meta::reflect_value(&noexcept_false_function)))); static_assert( !is_noexcept(type_of(std::meta::reflect_value(¬_noexcept_function)))); -// (no-)noexcept instantiated template functions -static_assert(is_noexcept(^noexcept_template_function)); -static_assert(is_noexcept(^noexcept_true_template_function)); -static_assert(!is_noexcept(^noexcept_false_template_function)); -static_assert(!is_noexcept(^not_noexcept_template_function)); - -// (no-)noexcept instantiated template function types -static_assert(is_noexcept(type_of(^noexcept_template_function))); -static_assert(is_noexcept(type_of(^noexcept_true_template_function))); -static_assert(!is_noexcept(type_of(^noexcept_false_template_function))); -static_assert(!is_noexcept(type_of(^not_noexcept_template_function))); - // (no-)noexcept instantiated template function pointers static_assert( - is_noexcept(std::meta::reflect_value(&noexcept_template_function))); -static_assert( - is_noexcept(std::meta::reflect_value(&noexcept_true_template_function))); + !is_noexcept(std::meta::reflect_value(&noexcept_template_function))); +static_assert(!is_noexcept( + std::meta::reflect_value(&noexcept_true_template_function))); static_assert(!is_noexcept( std::meta::reflect_value(&noexcept_false_template_function))); static_assert( !is_noexcept(std::meta::reflect_value(¬_noexcept_template_function))); // (no-)noexcept instantiated template function pointer types -static_assert(is_noexcept( +static_assert(!is_noexcept( type_of(std::meta::reflect_value(&noexcept_template_function)))); -static_assert(is_noexcept( +static_assert(!is_noexcept( type_of(std::meta::reflect_value(&noexcept_true_template_function)))); static_assert(!is_noexcept( type_of(std::meta::reflect_value(&noexcept_false_template_function)))); static_assert(!is_noexcept( type_of(std::meta::reflect_value(¬_noexcept_template_function)))); -// The rest (should all be false regardless of noexcept specifier) // (no-)noexcept non-instantiated template methods static_assert(!is_noexcept(^S::noexcept_template_method)); static_assert(!is_noexcept(^S::not_noexcept_template_method)); From bde2c6008eb0cdf6f3a598ff0ac06cc7e289bd1c Mon Sep 17 00:00:00 2001 From: delimbetov <1starfall1@gmail.com> Date: Mon, 1 Jul 2024 18:21:32 +0100 Subject: [PATCH 11/12] remove lambda from the func name --- clang/lib/Sema/Metafunctions.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clang/lib/Sema/Metafunctions.cpp b/clang/lib/Sema/Metafunctions.cpp index 085477a996a16f..3e169d8dee2fd9 100644 --- a/clang/lib/Sema/Metafunctions.cpp +++ b/clang/lib/Sema/Metafunctions.cpp @@ -1108,7 +1108,7 @@ bool isAccessible(Sema &S, DeclContext *AccessDC, NamedDecl *D) { return Result; } -static bool isFunctionOrLambdaNoexcept(const QualType QT) { +static bool isFunctionOrMethodNoexcept(const QualType QT) { const Type* T = QT.getTypePtr(); if (T->isFunctionProtoType()) { @@ -2688,13 +2688,13 @@ bool is_noexcept(APValue &Result, Sema &S, EvalFn Evaluator, QualType ResultTy, return SetAndSucceed(Result, makeBool(S.Context, false)); case ReflectionValue::RK_type: { const QualType QT = R.getReflectedType(); - const auto result = isFunctionOrLambdaNoexcept(QT); + const auto result = isFunctionOrMethodNoexcept(QT); return SetAndSucceed(Result, makeBool(S.Context, result)); } case ReflectionValue::RK_declaration: { const ValueDecl *D = R.getReflectedDecl(); - const auto result = isFunctionOrLambdaNoexcept(D->getType()); + const auto result = isFunctionOrMethodNoexcept(D->getType()); return SetAndSucceed(Result, makeBool(S.Context, result)); } From 6b31ff4e3a770e224fde4d405ac3d1be313ed6ce Mon Sep 17 00:00:00 2001 From: delimbetov <1starfall1@gmail.com> Date: Mon, 1 Jul 2024 18:52:00 +0100 Subject: [PATCH 12/12] Update meta comment to match changed specs --- libcxx/include/experimental/meta | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libcxx/include/experimental/meta b/libcxx/include/experimental/meta index c46ea47df861c6..5a495227a04295 100644 --- a/libcxx/include/experimental/meta +++ b/libcxx/include/experimental/meta @@ -909,8 +909,8 @@ consteval auto is_explicit(info r) -> bool { return __metafunction(detail::__metafn_is_explicit, r); } -// Returns whether the reflected function, function pointer, function type, -// non-generic lambda expression, or non-generic closure type is noexcept. +// Returns whether the reflected function type, function or member function +// is noexcept. consteval auto is_noexcept(info r) -> bool { return __metafunction(detail::__metafn_is_noexcept, r); }