Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue #88: Add has_{thread,automatic}_storage_duration functions #89

Merged
merged 5 commits into from
Aug 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions clang/lib/Sema/Metafunctions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,16 @@ static bool has_static_storage_duration(APValue &Result, Sema &S,
QualType ResultTy, SourceRange Range,
ArrayRef<Expr *> Args);

static bool has_thread_storage_duration(APValue &Result, Sema &S,
EvalFn Evaluator, DiagFn Diagnoser,
QualType ResultTy, SourceRange Range,
ArrayRef<Expr *> Args);

static bool has_automatic_storage_duration(APValue &Result, Sema &S,
EvalFn Evaluator, DiagFn Diagnoser,
QualType ResultTy, SourceRange Range,
ArrayRef<Expr *> Args);

static bool has_internal_linkage(APValue &Result, Sema &S, EvalFn Evaluator,
DiagFn Diagnoser, QualType ResultTy,
SourceRange Range, ArrayRef<Expr *> Args);
Expand Down Expand Up @@ -518,6 +528,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 },
Expand Down Expand Up @@ -3419,6 +3431,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<Expr *> 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<VarDecl>(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<Expr *> 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<VarDecl>(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<Expr *> Args) {
Expand Down
1 change: 1 addition & 0 deletions libcxx/include/__std_clang_module
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@
#include <expected>
#include <experimental/iterator>
#include <experimental/memory>
#include <experimental/meta>
#include <experimental/propagate_const>
#include <experimental/simd>
#include <experimental/type_traits>
Expand Down
16 changes: 16 additions & 0 deletions libcxx/include/experimental/meta
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,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;
Expand Down Expand Up @@ -446,6 +448,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,
Expand Down Expand Up @@ -1021,6 +1025,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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<int, int> 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 <auto V> 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<S{}>)[0]));
static_assert(
!has_thread_storage_duration(template_arguments_of(^TCls<S{}>)[0]));
static_assert(
!has_automatic_storage_duration(template_arguments_of(^TCls<S{}>)[0]));

template <auto K> constexpr auto R = ^K;
static_assert(has_static_storage_duration(R<S{}>));
static_assert(!has_thread_storage_duration(R<S{}>));
static_assert(!has_automatic_storage_duration(R<S{}>));

static std::pair<int, int> 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

// =======
Expand Down
Loading