diff --git a/clang/lib/Sema/Metafunctions.cpp b/clang/lib/Sema/Metafunctions.cpp index f5daed8eb68108..3a3fd92181fe0a 100644 --- a/clang/lib/Sema/Metafunctions.cpp +++ b/clang/lib/Sema/Metafunctions.cpp @@ -213,6 +213,16 @@ static bool has_static_storage_duration(APValue &Result, Sema &S, QualType ResultTy, SourceRange Range, ArrayRef Args); +static bool has_thread_storage_duration(APValue &Result, Sema &S, + EvalFn Evaluator, DiagFn Diagnoser, + QualType ResultTy, SourceRange Range, + ArrayRef Args); + +static bool has_automatic_storage_duration(APValue &Result, Sema &S, + EvalFn Evaluator, DiagFn Diagnoser, + QualType ResultTy, SourceRange Range, + ArrayRef Args); + static bool has_internal_linkage(APValue &Result, Sema &S, EvalFn Evaluator, DiagFn Diagnoser, QualType ResultTy, SourceRange Range, ArrayRef Args); @@ -523,6 +533,8 @@ static constexpr Metafunction Metafunctions[] = { { Metafunction::MFRK_bool, 1, 1, is_lvalue_reference_qualified }, { Metafunction::MFRK_bool, 1, 1, is_rvalue_reference_qualified }, { Metafunction::MFRK_bool, 1, 1, has_static_storage_duration }, + { Metafunction::MFRK_bool, 1, 1, has_thread_storage_duration }, + { Metafunction::MFRK_bool, 1, 1, has_automatic_storage_duration }, { Metafunction::MFRK_bool, 1, 1, has_internal_linkage }, { Metafunction::MFRK_bool, 1, 1, has_module_linkage }, { Metafunction::MFRK_bool, 1, 1, has_external_linkage }, @@ -3477,6 +3489,44 @@ bool has_static_storage_duration(APValue &Result, Sema &S, EvalFn Evaluator, return SetAndSucceed(Result, makeBool(S.Context, result)); } +bool has_thread_storage_duration(APValue &Result, Sema &S, + EvalFn Evaluator, DiagFn Diagnoser, + QualType ResultTy, SourceRange Range, + ArrayRef Args) { + assert(Args[0]->getType()->isReflectionType()); + assert(ResultTy == S.Context.BoolTy); + + APValue RV; + if (!Evaluator(RV, Args[0], true)) + return true; + + bool result = false; + if (RV.isReflectedDecl()) { + if (const auto *VD = dyn_cast(RV.getReflectedDecl())) + result = VD->getStorageDuration() == SD_Thread; + } + return SetAndSucceed(Result, makeBool(S.Context, result)); +} + +bool has_automatic_storage_duration(APValue &Result, Sema &S, + EvalFn Evaluator, DiagFn Diagnoser, + QualType ResultTy, SourceRange Range, + ArrayRef Args) { + assert(Args[0]->getType()->isReflectionType()); + assert(ResultTy == S.Context.BoolTy); + + APValue RV; + if (!Evaluator(RV, Args[0], true)) + return true; + + bool result = false; + if (RV.isReflectedDecl()) { + if (const auto *VD = dyn_cast(RV.getReflectedDecl())) + result = VD->getStorageDuration() == SD_Automatic; + } + return SetAndSucceed(Result, makeBool(S.Context, result)); +} + bool has_internal_linkage(APValue &Result, Sema &S, EvalFn Evaluator, DiagFn Diagnoser, QualType ResultTy, SourceRange Range, ArrayRef Args) { diff --git a/libcxx/include/experimental/meta b/libcxx/include/experimental/meta index 400fab69fa36d8..199ffb6e4ead55 100644 --- a/libcxx/include/experimental/meta +++ b/libcxx/include/experimental/meta @@ -141,6 +141,8 @@ consteval auto is_volatile(info) -> bool; consteval auto is_lvalue_reference_qualified(info) -> bool; consteval auto is_rvalue_reference_qualified(info) -> bool; consteval auto has_static_storage_duration(info) -> bool; +consteval auto has_thread_storage_duration(info r) -> bool; +consteval auto has_automatic_storage_duration(info r) -> bool; consteval auto has_internal_linkage(info) -> bool; consteval auto has_module_linkage(info) -> bool; consteval auto has_external_linkage(info) -> bool; @@ -449,6 +451,8 @@ enum : unsigned { __metafn_is_lvalue_reference_qualified, __metafn_is_rvalue_reference_qualified, __metafn_has_static_storage_duration, + __metafn_has_thread_storage_duration, + __metafn_has_automatic_storage_duration, __metafn_has_internal_linkage, __metafn_has_module_linkage, __metafn_has_external_linkage, @@ -1029,6 +1033,18 @@ consteval auto has_static_storage_duration(info r) -> bool { return __metafunction(detail::__metafn_has_static_storage_duration, r); } +// Returns whether the reflected entity is a variable having thread storage +// duration. +consteval auto has_thread_storage_duration(info r) -> bool { + return __metafunction(detail::__metafn_has_thread_storage_duration, r); +} + +// Returns whether the reflected entity is a variable having automatic storage +// duration. +consteval auto has_automatic_storage_duration(info r) -> bool { + return __metafunction(detail::__metafn_has_automatic_storage_duration, r); +} + // Returns whether the reflected entity has internal linkage. consteval auto has_internal_linkage(info r) -> bool { return __metafunction(detail::__metafn_has_internal_linkage, r); diff --git a/libcxx/test/std/experimental/reflection/linkage-and-storage-class.pass.cpp b/libcxx/test/std/experimental/reflection/linkage-and-storage-class.pass.cpp index 16eee385e2c0c7..ce599353358f00 100644 --- a/libcxx/test/std/experimental/reflection/linkage-and-storage-class.pass.cpp +++ b/libcxx/test/std/experimental/reflection/linkage-and-storage-class.pass.cpp @@ -29,47 +29,133 @@ namespace storage_class_and_duration { struct S { int nsdm; static_assert(!has_static_storage_duration(^nsdm)); + static_assert(!has_thread_storage_duration(^nsdm)); + static_assert(!has_automatic_storage_duration(^nsdm)); static_assert(is_nonstatic_data_member(^nsdm)); static_assert(!is_static_member(^nsdm)); static inline int sdm; static_assert(has_static_storage_duration(^sdm)); + static_assert(!has_thread_storage_duration(^sdm)); + static_assert(!has_automatic_storage_duration(^sdm)); static_assert(!is_nonstatic_data_member(^sdm)); static_assert(is_static_member(^sdm)); + + static thread_local int stdm; + static_assert(!has_static_storage_duration(^stdm)); + static_assert(has_thread_storage_duration(^stdm)); + static_assert(!has_automatic_storage_duration(^stdm)); + static_assert(!is_nonstatic_data_member(^stdm)); + static_assert(is_static_member(^stdm)); }; +extern int i0; +static_assert(has_static_storage_duration(^i0)); +static_assert(!has_thread_storage_duration(^i0)); +static_assert(!has_automatic_storage_duration(^i0)); + int i1; static_assert(has_static_storage_duration(^i1)); +static_assert(!has_thread_storage_duration(^i1)); +static_assert(!has_automatic_storage_duration(^i1)); static int i2; static_assert(has_static_storage_duration(^i2)); +static_assert(!has_thread_storage_duration(^i2)); +static_assert(!has_automatic_storage_duration(^i2)); thread_local int i3; static_assert(!has_static_storage_duration(^i3)); +static_assert(has_thread_storage_duration(^i3)); +static_assert(!has_automatic_storage_duration(^i3)); static thread_local int i4; static_assert(!has_static_storage_duration(^i4)); +static_assert(has_thread_storage_duration(^i4)); +static_assert(!has_automatic_storage_duration(^i4)); + +void foo(float parameter_var) { + static_assert(!has_static_storage_duration(^parameter_var)); + static_assert(!has_thread_storage_duration(^parameter_var)); + static_assert(has_automatic_storage_duration(^parameter_var)); -void foo() { int nonstatic_var; static_assert(!has_static_storage_duration(^nonstatic_var)); + static_assert(!has_thread_storage_duration(^nonstatic_var)); + static_assert(has_automatic_storage_duration(^nonstatic_var)); + + int& ref_to_nonstatic_var = nonstatic_var; + static_assert(!has_static_storage_duration(^ref_to_nonstatic_var)); + static_assert(!has_thread_storage_duration(^ref_to_nonstatic_var)); + static_assert(has_automatic_storage_duration(^ref_to_nonstatic_var)); + + // assert the funcs check SD of the reference instead of the target object + static int& static_ref_to_var = nonstatic_var; + static_assert(has_static_storage_duration(^static_ref_to_var)); + static_assert(!has_thread_storage_duration(^static_ref_to_var)); + static_assert(!has_automatic_storage_duration(^static_ref_to_var)); static int static_var; static_assert(has_static_storage_duration(^static_var)); + static_assert(!has_thread_storage_duration(^static_var)); + static_assert(!has_automatic_storage_duration(^static_var)); + + int& ref_to_static_var = static_var; + static_assert(!has_static_storage_duration(^ref_to_static_var)); + static_assert(!has_thread_storage_duration(^ref_to_static_var)); + static_assert(has_automatic_storage_duration(^ref_to_static_var)); + + thread_local int tl_var; + static_assert(!has_static_storage_duration(^tl_var)); + static_assert(has_thread_storage_duration(^tl_var)); + static_assert(!has_automatic_storage_duration(^tl_var)); + + std::pair p; + auto [aa, ab] = p; + static_assert(!has_static_storage_duration(^aa)); + static_assert(!has_thread_storage_duration(^aa)); + static_assert(!has_automatic_storage_duration(^aa)); + + static auto [sa, sb] = p; + static_assert(!has_static_storage_duration(^sa)); + static_assert(!has_thread_storage_duration(^sa)); + static_assert(!has_automatic_storage_duration(^sa)); + + thread_local auto [ta, tb] = p; + static_assert(!has_static_storage_duration(^ta)); + static_assert(!has_thread_storage_duration(^ta)); + static_assert(!has_automatic_storage_duration(^ta)); } template struct TCls {}; static_assert(!has_static_storage_duration(template_arguments_of(^TCls<5>)[0])); +static_assert( + !has_thread_storage_duration(template_arguments_of(^TCls<5>)[0])); +static_assert( + !has_automatic_storage_duration(template_arguments_of(^TCls<5>)[0])); + +static_assert( + has_static_storage_duration(template_arguments_of(^TCls)[0])); +static_assert( + !has_thread_storage_duration(template_arguments_of(^TCls)[0])); +static_assert( + !has_automatic_storage_duration(template_arguments_of(^TCls)[0])); template constexpr auto R = ^K; static_assert(has_static_storage_duration(R)); +static_assert(!has_thread_storage_duration(R)); +static_assert(!has_automatic_storage_duration(R)); static std::pair p; constexpr auto first = std::meta::reflect_object(p.first); static_assert(has_static_storage_duration(first)); +static_assert(!has_thread_storage_duration(first)); +static_assert(!has_automatic_storage_duration(first)); static_assert(!has_static_storage_duration(std::meta::reflect_value(4))); +static_assert(!has_thread_storage_duration(std::meta::reflect_value(4))); +static_assert(!has_automatic_storage_duration(std::meta::reflect_value(4))); } // namespace storage_class_and_duration // =======