Skip to content

Commit

Permalink
Issue #88: Add has_{thread,automatic}_storage_duration functions (#89)
Browse files Browse the repository at this point in the history
* basic impl

Signed-off-by: delimbetov <1starfall1@gmail.com>

* add test for the new storage duration funcs

Signed-off-by: delimbetov <1starfall1@gmail.com>

* code style

Signed-off-by: delimbetov <1starfall1@gmail.com>

* run libcxx generators to pass CI

Signed-off-by: delimbetov <1starfall1@gmail.com>

* fix identation

Signed-off-by: delimbetov <1starfall1@gmail.com>

---------

Signed-off-by: delimbetov <1starfall1@gmail.com>
  • Loading branch information
delimbetov authored Aug 19, 2024
1 parent 3d897ec commit 33bebfb
Show file tree
Hide file tree
Showing 3 changed files with 153 additions and 1 deletion.
50 changes: 50 additions & 0 deletions clang/lib/Sema/Metafunctions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,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 @@ -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 },
Expand Down Expand Up @@ -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<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
16 changes: 16 additions & 0 deletions libcxx/include/experimental/meta
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);
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

0 comments on commit 33bebfb

Please sign in to comment.