Files
clang-p2996/libcxx/test/std/experimental/reflection/p3096-fn-parameters.pass.cpp
2025-06-24 11:01:59 -04:00

307 lines
12 KiB
C++

//===----------------------------------------------------------------------===//
//
// Copyright 2024 Bloomberg Finance L.P.
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03 || c++11 || c++14 || c++17 || c++20
// ADDITIONAL_COMPILE_FLAGS: -freflection
// ADDITIONAL_COMPILE_FLAGS: -fparameter-reflection
// <experimental/reflection>
//
// [reflection]
#include <meta>
constexpr auto ctx = std::meta::access_context::unchecked();
// =================
// with_no_arguments
// =================
namespace with_no_arguments {
void fn();
template <typename... Ts>
void tfn(Ts...);
static_assert(parameters_of(^^fn).size() == 0);
static_assert(parameters_of(^^tfn<>).size() == 0);
static_assert(!has_ellipsis_parameter(^^tfn<>));
static_assert(!has_ellipsis_parameter(type_of(^^tfn<>)));
static_assert(return_type_of(^^fn) == ^^void);
static_assert(return_type_of(^^tfn<>) == ^^void);
} // namespace with_no_arguments
// ====================
// with_fixed_arguments
// ====================
namespace with_fixed_arguments {
template <typename T>
struct S {};
void fn(int a, bool b, const S<int> &s);
static_assert(parameters_of(^^fn).size() == 3);
static_assert(parameters_of(type_of(^^fn)) ==
std::vector {^^int, ^^bool, ^^const S<int> &});
static_assert(type_of(parameters_of(^^fn)[0]) == ^^int);
static_assert(identifier_of(parameters_of(^^fn)[0]) == "a");
static_assert(has_identifier(parameters_of(^^fn)[0]));
static_assert(!has_default_argument(parameters_of(^^fn)[0]));
static_assert(!is_explicit_object_parameter(parameters_of(^^fn)[0]));
static_assert(type_of(parameters_of(^^fn)[1]) == ^^bool);
static_assert(identifier_of(parameters_of(^^fn)[1]) == "b");
static_assert(has_identifier(parameters_of(^^fn)[1]));
static_assert(!has_default_argument(parameters_of(^^fn)[1]));
static_assert(!is_explicit_object_parameter(parameters_of(^^fn)[1]));
static_assert(type_of(parameters_of(^^fn)[2]) == ^^const S<int> &);
static_assert(identifier_of(parameters_of(^^fn)[2]) == "s");
static_assert(has_identifier(parameters_of(^^fn)[2]));
static_assert(!has_default_argument(parameters_of(^^fn)[2]));
static_assert(!is_explicit_object_parameter(parameters_of(^^fn)[2]));
static_assert(!has_ellipsis_parameter(^^fn));
static_assert(!has_ellipsis_parameter(type_of(^^fn)));
static_assert(return_type_of(^^fn) == ^^void);
} // namespace with_fixed_arguments
// =====================
// with_member_functions
// =====================
namespace with_member_functions {
struct Cls {
Cls(int a);
~Cls();
int fn(int a, bool b = false);
bool fn2(this Cls &self, int, ...);
static Cls &sfn(int a, ...);
};
constexpr auto ctor =
(members_of(^^Cls, ctx) |
std::views::filter(std::meta::is_constructor)).front();
static_assert(parameters_of(ctor).size() == 1);
static_assert(type_of(parameters_of(ctor)[0]) == ^^int);
static_assert(identifier_of(parameters_of(ctor)[0]) == "a");
static_assert(has_identifier(parameters_of(ctor)[0]));
static_assert(!has_default_argument(parameters_of(ctor)[0]));
static_assert(!is_explicit_object_parameter(parameters_of(ctor)[0]));
static_assert(!has_ellipsis_parameter(ctor));
constexpr auto dtor =
(members_of(^^Cls, ctx) |
std::views::filter(std::meta::is_destructor)).front();
static_assert(parameters_of(dtor).size() == 0);
static_assert(!has_ellipsis_parameter(dtor));
static_assert(parameters_of(^^Cls::fn).size() == 2);
static_assert(parameters_of(type_of(^^Cls::fn)) == std::vector {^^int, ^^bool});
static_assert(type_of(parameters_of(^^Cls::fn)[0]) == ^^int);
static_assert(identifier_of(parameters_of(^^Cls::fn)[0]) == "a");
static_assert(has_identifier(parameters_of(^^Cls::fn)[0]));
static_assert(!has_default_argument(parameters_of(^^Cls::fn)[0]));
static_assert(!is_explicit_object_parameter(parameters_of(^^Cls::fn)[0]));
static_assert(type_of(parameters_of(^^Cls::fn)[1]) == ^^bool);
static_assert(identifier_of(parameters_of(^^Cls::fn)[1]) == "b");
static_assert(has_identifier(parameters_of(^^Cls::fn)[1]));
static_assert(has_default_argument(parameters_of(^^Cls::fn)[1]));
static_assert(!is_explicit_object_parameter(parameters_of(^^Cls::fn)[1]));
static_assert(!has_ellipsis_parameter(^^Cls::fn));
static_assert(!has_ellipsis_parameter(type_of(^^Cls::fn)));
static_assert(return_type_of(^^Cls::fn) == ^^int);
static_assert(parameters_of(^^Cls::fn2).size() == 2);
static_assert(parameters_of(type_of(^^Cls::fn2)) ==
std::vector {^^Cls &, ^^int});
static_assert(type_of(parameters_of(^^Cls::fn2)[0]) == ^^Cls &);
static_assert(identifier_of(parameters_of(^^Cls::fn2)[0]) == "self");
static_assert(has_identifier(parameters_of(^^Cls::fn2)[0]));
static_assert(!has_default_argument(parameters_of(^^Cls::fn2)[0]));
static_assert(is_explicit_object_parameter(parameters_of(^^Cls::fn2)[0]));
static_assert(type_of(parameters_of(^^Cls::fn2)[1]) == ^^int);
static_assert(!has_identifier(parameters_of(^^Cls::fn2)[1]));
static_assert(!has_default_argument(parameters_of(^^Cls::fn2)[1]));
static_assert(has_ellipsis_parameter(^^Cls::fn2));
static_assert(has_ellipsis_parameter(type_of(^^Cls::fn2)));
static_assert(!is_explicit_object_parameter(parameters_of(^^Cls::fn2)[1]));
static_assert(return_type_of(^^Cls::fn2) == ^^bool);
static_assert(parameters_of(^^Cls::sfn).size() == 1);
static_assert(parameters_of(type_of(^^Cls::sfn)) == std::vector {^^int});
static_assert(type_of(parameters_of(^^Cls::sfn)[0]) == ^^int);
static_assert(identifier_of(parameters_of(^^Cls::sfn)[0]) == "a");
static_assert(has_identifier(parameters_of(^^Cls::sfn)[0]));
static_assert(!has_default_argument(parameters_of(^^Cls::sfn)[0]));
static_assert(!is_explicit_object_parameter(parameters_of(^^Cls::sfn)[0]));
static_assert(has_ellipsis_parameter(^^Cls::sfn));
static_assert(has_ellipsis_parameter(type_of(^^Cls::sfn)));
static_assert(return_type_of(^^Cls::sfn) == ^^Cls&);
} // namespace with_member_functions
// ===========================
// with_template_instantiation
// ===========================
namespace with_template_instantiation {
template <typename... Ts>
std::tuple<Ts *...> fn(Ts &&... ts);
template <std::meta::info TFn, typename... Ts> // check with dependent names.
consteval bool check() {
constexpr auto Fn = substitute(TFn, {^^Ts...});
static_assert(parameters_of(Fn).size() == 3);
static_assert(parameters_of(type_of(Fn)) ==
std::vector {^^int &&, ^^char &&, ^^bool &&});
static_assert(type_of(parameters_of(Fn)[0]) == ^^int &&);
static_assert(identifier_of(parameters_of(Fn)[0]) == "ts");
static_assert(has_identifier(parameters_of(Fn)[0]));
static_assert(!has_default_argument(parameters_of(Fn)[0]));
static_assert(!is_explicit_object_parameter(parameters_of(Fn)[0]));
static_assert(type_of(parameters_of(Fn)[1]) == ^^char &&);
static_assert(identifier_of(parameters_of(Fn)[1]) == "ts");
static_assert(has_identifier(parameters_of(Fn)[1]));
static_assert(!has_default_argument(parameters_of(Fn)[1]));
static_assert(!is_explicit_object_parameter(parameters_of(Fn)[1]));
static_assert(type_of(parameters_of(Fn)[2]) == ^^bool &&);
static_assert(identifier_of(parameters_of(Fn)[2]) == "ts");
static_assert(has_identifier(parameters_of(Fn)[2]));
static_assert(!has_default_argument(parameters_of(Fn)[2]));
static_assert(!is_explicit_object_parameter(parameters_of(Fn)[2]));
static_assert(!has_ellipsis_parameter(Fn));
static_assert(!has_ellipsis_parameter(type_of(Fn)));
static_assert(return_type_of(Fn) == ^^std::tuple<int *, char *, bool *>);
return true;
}
static_assert(check<^^fn, int, char, bool>());
} // namespace with_template_instantiation
// ======================
// with_default_arguments
// ======================
namespace with_default_arguments {
// Ensure 'has_default_argument' "sees through" redeclarations that omit them.
void fn(int a, bool b);
void fn(int a, bool b = false);
void fn(int a, bool b);
static_assert(parameters_of(^^fn).size() == 2);
static_assert(parameters_of(type_of(^^fn)) == std::vector {^^int, ^^bool});
static_assert(type_of(parameters_of(^^fn)[0]) == ^^int);
static_assert(identifier_of(parameters_of(^^fn)[0]) == "a");
static_assert(has_identifier(parameters_of(^^fn)[0]));
static_assert(!has_default_argument(parameters_of(^^fn)[0]));
static_assert(!is_explicit_object_parameter(parameters_of(^^fn)[0]));
static_assert(type_of(parameters_of(^^fn)[1]) == ^^bool);
static_assert(identifier_of(parameters_of(^^fn)[1]) == "b");
static_assert(has_identifier(parameters_of(^^fn)[1]));
static_assert(has_default_argument(parameters_of(^^fn)[1]));
static_assert(!is_explicit_object_parameter(parameters_of(^^fn)[1]));
static_assert(!has_ellipsis_parameter(^^fn));
static_assert(!has_ellipsis_parameter(type_of(^^fn)));
} // namespace with_default_arguments
// ====================
// with_ambiguous_names
// ====================
namespace with_ambiguous_names {
void fn(int a1, bool b, char c1);
static_assert(has_identifier(parameters_of(^^fn)[2]));
void fn(int a2, bool, char c2);
constexpr auto r_a2 = parameters_of(^^fn)[0];
static_assert(identifier_of(parameters_of(^^fn)[1]) == "b");
void fn(int a3, bool b, char c1);
constexpr auto r_a3 = parameters_of(^^fn)[0];
static_assert(parameters_of(^^fn).size() == 3);
static_assert(parameters_of(type_of(^^fn)) ==
std::vector {^^int, ^^bool, ^^char});
static_assert(!has_identifier(parameters_of(^^fn)[0]));
static_assert(identifier_of(parameters_of(^^fn)[1]) == "b");
static_assert(has_identifier(parameters_of(^^fn)[1]));
static_assert(!has_identifier(parameters_of(^^fn)[2]));
static_assert(r_a2 == r_a3);
} // namespace with_ambiguous_names
// =================
// type_and_cv_decay
// =================
namespace with_ambiguous_types {
using Alias = int;
void fn(Alias, const bool, char [], char &);
static_assert(type_of(parameters_of(^^fn)[0]) == ^^int);
static_assert(type_of(parameters_of(^^fn)[1]) == ^^bool);
static_assert(type_of(parameters_of(^^fn)[2]) == ^^char *);
static_assert(type_of(parameters_of(^^fn)[3]) == ^^char &);
static_assert(!is_const(parameters_of(^^fn)[1]));
} // namespace with_ambiguous_types
// ============================
// identify_function_parameters
// ============================
namespace identify_function_parameters {
void fn(int a, bool &b, std::string *, ...);
static_assert(is_function_parameter(parameters_of(^^fn)[0]));
static_assert(is_function_parameter(parameters_of(^^fn)[1]));
static_assert(is_function_parameter(parameters_of(^^fn)[2]));
static_assert(!is_function_parameter(^^::));
static_assert(!is_function_parameter(^^int));
static_assert(!is_function_parameter(^^fn));
static_assert(!is_function_parameter(std::meta::reflect_constant(3)));
static_assert(has_ellipsis_parameter(type_of(^^fn)));
} // namespace identify_function_parameters
// =======================================
// mangle_reflection_of_function_parameter
// =======================================
namespace mangle_reflection_of_function_parameter {
template <auto R> void fn() {}
void user(int) {
fn<parameters_of(^^user)[0]>();
}
} // namespace mangle_reflection_of_function_parameter
// =================
// variable_of_tests
// =================
namespace variable_of_tests {
consteval int fn(int p) {
constexpr auto rp = parameters_of(^^fn)[0];
constexpr auto rv = variable_of(rp);
static_assert(is_function_parameter(rp));
static_assert(!is_function_parameter(rv));
static_assert(!is_variable(rp));
static_assert(is_variable(rv));
static_assert(^^p == rv);
return [:variable_of(parameters_of(^^fn)[0]):];
}
static_assert(fn(42) == 42);
} // namespace variable_of_tests
int main() { }