Skip to content

Commit c683e64

Browse files
committed
Add 'is_const' and 'is_volatile' metafunctions.
Closes issues llvm#68 and llvm#69.
1 parent bfeb3a5 commit c683e64

File tree

3 files changed

+173
-3
lines changed

3 files changed

+173
-3
lines changed

clang/lib/Sema/Metafunctions.cpp

Lines changed: 100 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,14 @@ static bool is_bit_field(APValue &Result, Sema &S, EvalFn Evaluator,
167167
QualType ResultTy, SourceRange Range,
168168
ArrayRef<Expr *> Args);
169169

170+
static bool is_const(APValue &Result, Sema &S, EvalFn Evaluator,
171+
QualType ResultTy, SourceRange Range,
172+
ArrayRef<Expr *> Args);
173+
174+
static bool is_volatile(APValue &Result, Sema &S, EvalFn Evaluator,
175+
QualType ResultTy, SourceRange Range,
176+
ArrayRef<Expr *> Args);
177+
170178
static bool is_lvalue_reference_qualified(APValue &Result, Sema &S,
171179
EvalFn Evaluator, QualType ResultTy,
172180
SourceRange Range,
@@ -441,6 +449,8 @@ static constexpr Metafunction Metafunctions[] = {
441449
{ Metafunction::MFRK_bool, 1, 1, is_explicit },
442450
{ Metafunction::MFRK_bool, 1, 1, is_noexcept },
443451
{ Metafunction::MFRK_bool, 1, 1, is_bit_field },
452+
{ Metafunction::MFRK_bool, 1, 1, is_const },
453+
{ Metafunction::MFRK_bool, 1, 1, is_volatile },
444454
{ Metafunction::MFRK_bool, 1, 1, is_lvalue_reference_qualified },
445455
{ Metafunction::MFRK_bool, 1, 1, is_rvalue_reference_qualified },
446456
{ Metafunction::MFRK_bool, 1, 1, has_static_storage_duration },
@@ -597,9 +607,9 @@ static void encodeName(std::string &Result, StringRef In, bool BasicOnly) {
597607
Result = In;
598608
} else {
599609
Result.reserve(In.size() * 8); // more than enough for '\u{XYZ}'
600-
610+
601611
llvm::raw_string_ostream OS(Result);
602-
612+
603613
const char *InCursor = In.begin();
604614
while (InCursor < In.end()) {
605615
if (isBasicCharacter(*InCursor)) {
@@ -1175,6 +1185,22 @@ static bool isFunctionOrMethodNoexcept(const QualType QT) {
11751185
return false;
11761186
}
11771187

1188+
static bool isConstQualifiedType(QualType QT) {
1189+
bool result = QT.isConstQualified();
1190+
if (auto *FPT = dyn_cast<FunctionProtoType>(QT))
1191+
result |= FPT->isConst();
1192+
1193+
return result;
1194+
}
1195+
1196+
static bool isVolatileQualifiedType(QualType QT) {
1197+
bool result = QT.isVolatileQualified();
1198+
if (auto *FPT = dyn_cast<FunctionProtoType>(QT))
1199+
result |= FPT->isVolatile();
1200+
1201+
return result;
1202+
}
1203+
11781204
// -----------------------------------------------------------------------------
11791205
// Metafunction implementations
11801206
// -----------------------------------------------------------------------------
@@ -2747,7 +2773,7 @@ bool is_noexcept(APValue &Result, Sema &S, EvalFn Evaluator, QualType ResultTy,
27472773
case ReflectionValue::RK_declaration: {
27482774
const ValueDecl *D = R.getReflectedDecl();
27492775
const auto result = isFunctionOrMethodNoexcept(D->getType());
2750-
2776+
27512777
return SetAndSucceed(Result, makeBool(S.Context, result));
27522778
}
27532779
}
@@ -2771,6 +2797,77 @@ bool is_bit_field(APValue &Result, Sema &S, EvalFn Evaluator, QualType ResultTy,
27712797
return SetAndSucceed(Result, makeBool(S.Context, result));
27722798
}
27732799

2800+
bool is_const(APValue &Result, Sema &S, EvalFn Evaluator, QualType ResultTy,
2801+
SourceRange Range, ArrayRef<Expr *> Args) {
2802+
assert(Args[0]->getType()->isReflectionType());
2803+
assert(ResultTy == S.Context.BoolTy);
2804+
2805+
APValue R;
2806+
if (!Evaluator(R, Args[0], true))
2807+
return true;
2808+
2809+
switch (R.getReflection().getKind()) {
2810+
case ReflectionValue::RK_null:
2811+
case ReflectionValue::RK_template:
2812+
case ReflectionValue::RK_namespace:
2813+
case ReflectionValue::RK_base_specifier:
2814+
case ReflectionValue::RK_data_member_spec:
2815+
return SetAndSucceed(Result, makeBool(S.Context, false));
2816+
case ReflectionValue::RK_type: {
2817+
bool result = isConstQualifiedType(R.getReflectedType());
2818+
2819+
return SetAndSucceed(Result, makeBool(S.Context, result));
2820+
}
2821+
case ReflectionValue::RK_declaration: {
2822+
bool result = isConstQualifiedType(R.getReflectedDecl()->getType());
2823+
2824+
return SetAndSucceed(Result, makeBool(S.Context, result));
2825+
}
2826+
case ReflectionValue::RK_expr_result: {
2827+
bool result = isConstQualifiedType(R.getReflectedExprResult()->getType());
2828+
2829+
return SetAndSucceed(Result, makeBool(S.Context, result));
2830+
}
2831+
}
2832+
llvm_unreachable("invalid reflection type");
2833+
}
2834+
2835+
bool is_volatile(APValue &Result, Sema &S, EvalFn Evaluator, QualType ResultTy,
2836+
SourceRange Range, ArrayRef<Expr *> Args) {
2837+
assert(Args[0]->getType()->isReflectionType());
2838+
assert(ResultTy == S.Context.BoolTy);
2839+
2840+
APValue R;
2841+
if (!Evaluator(R, Args[0], true))
2842+
return true;
2843+
2844+
switch (R.getReflection().getKind()) {
2845+
case ReflectionValue::RK_null:
2846+
case ReflectionValue::RK_template:
2847+
case ReflectionValue::RK_namespace:
2848+
case ReflectionValue::RK_base_specifier:
2849+
case ReflectionValue::RK_data_member_spec:
2850+
return SetAndSucceed(Result, makeBool(S.Context, false));
2851+
case ReflectionValue::RK_type: {
2852+
bool result = isVolatileQualifiedType(R.getReflectedType());
2853+
2854+
return SetAndSucceed(Result, makeBool(S.Context, result));
2855+
}
2856+
case ReflectionValue::RK_declaration: {
2857+
bool result = isVolatileQualifiedType(R.getReflectedDecl()->getType());
2858+
2859+
return SetAndSucceed(Result, makeBool(S.Context, result));
2860+
}
2861+
case ReflectionValue::RK_expr_result: {
2862+
bool result =
2863+
isVolatileQualifiedType(R.getReflectedExprResult()->getType());
2864+
2865+
return SetAndSucceed(Result, makeBool(S.Context, result));
2866+
}
2867+
}
2868+
llvm_unreachable("invalid reflection type");
2869+
}
2870+
27742871
bool is_lvalue_reference_qualified(APValue &Result, Sema &S, EvalFn Evaluator,
27752872
QualType ResultTy, SourceRange Range,
27762873
ArrayRef<Expr *> Args) {

libcxx/include/experimental/meta

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ consteval auto is_defaulted(info) -> bool;
118118
consteval auto is_explicit(info) -> bool;
119119
consteval bool is_noexcept(info) -> bool;
120120
consteval auto is_bit_field(info) -> bool;
121+
consteval auto is_const(info) -> bool;
122+
consteval auto is_volatile(info) -> bool;
121123
consteval auto is_lvalue_reference_qualified(info) -> bool;
122124
consteval auto is_rvalue_reference_qualified(info) -> bool;
123125
consteval auto has_static_storage_duration(info) -> bool;
@@ -402,6 +404,8 @@ enum : unsigned {
402404
__metafn_is_explicit,
403405
__metafn_is_noexcept,
404406
__metafn_is_bit_field,
407+
__metafn_is_const,
408+
__metafn_is_volatile,
405409
__metafn_is_lvalue_reference_qualified,
406410
__metafn_is_rvalue_reference_qualified,
407411
__metafn_has_static_storage_duration,
@@ -934,6 +938,18 @@ consteval auto is_bit_field(info r) -> bool {
934938
return __metafunction(detail::__metafn_is_bit_field, r);
935939
}
936940

941+
// Returns whether the reflected type is const-qualified, or if the reflected
942+
// entity is of such a type.
943+
consteval auto is_const(info r) -> bool {
944+
return __metafunction(detail::__metafn_is_const, r);
945+
}
946+
947+
// Returns whether the reflected type is volatile-qualified, or if the reflected
948+
// entity is of such a type.
949+
consteval auto is_volatile(info r) -> bool {
950+
return __metafunction(detail::__metafn_is_volatile, r);
951+
}
952+
937953
// Returns whether the reflected member function or function type is
938954
// lvalue-reference qualified.
939955
consteval auto is_lvalue_reference_qualified(info r) -> bool {

libcxx/test/std/experimental/reflection/member-classification.pass.cpp

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -861,4 +861,61 @@ static_assert(!has_default_member_initializer(^int));
861861
static_assert(!has_default_member_initializer(^::));
862862
} // namespace member_initializers
863863

864+
// ==================
865+
// const_and_volatile
866+
// ==================
867+
868+
namespace const_and_volatile {
869+
870+
struct S {
871+
void fn1();
872+
void fn2() const;
873+
void fn3() volatile;
874+
};
875+
876+
int v1;
877+
878+
const int v2 = 0;
879+
const int arr1[] = {1, 2};
880+
881+
volatile int v3;
882+
volatile int arr2[] = {1, 2};
883+
884+
static_assert(!is_const(^S::fn1));
885+
static_assert(is_const(^S::fn2));
886+
static_assert(!is_const(^S::fn3));
887+
888+
static_assert(!is_const(^v1));
889+
static_assert(is_const(^v2));
890+
static_assert(is_const(^arr1));
891+
static_assert(is_const(std::meta::reflect_object(arr1[1])));
892+
static_assert(!is_const(^v3));
893+
static_assert(!is_const(^arr2));
894+
static_assert(!is_const(std::meta::reflect_object(arr2[1])));
895+
896+
static_assert(!is_volatile(^S::fn1));
897+
static_assert(!is_volatile(^S::fn2));
898+
static_assert(is_volatile(^S::fn3));
899+
900+
static_assert(!is_volatile(^v1));
901+
static_assert(!is_volatile(^v2));
902+
static_assert(!is_volatile(^arr1));
903+
static_assert(!is_volatile(std::meta::reflect_object(arr1[1])));
904+
static_assert(is_volatile(^v3));
905+
static_assert(is_volatile(^arr2));
906+
static_assert(is_volatile(std::meta::reflect_object(arr2[1])));
907+
908+
static_assert(!is_const(^int));
909+
static_assert(is_const(^const int));
910+
static_assert(is_const(^const volatile int));
911+
static_assert(!is_const(^volatile int));
912+
static_assert(is_const(^void() const));
913+
914+
static_assert(!is_volatile(^int));
915+
static_assert(!is_volatile(^const int));
916+
static_assert(is_volatile(^const volatile int));
917+
static_assert(is_volatile(^volatile int));
918+
static_assert(is_volatile(^void() volatile));
919+
} // namespace const_and_volatile
920+
864921
int main() { }

0 commit comments

Comments
 (0)