Files
clang-p2996/clang/test/Reflection/splice-exprs.cpp
2025-05-21 11:31:24 -04:00

390 lines
10 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
//
//===----------------------------------------------------------------------===//
//
// RUN: %clang_cc1 %s -std=c++26 -freflection -fentity-proxy-reflection -verify
using info = decltype(^^int);
namespace anon_union_member_splice {
struct C {
union {
int i;
};
};
auto c = C{.i=2};
auto v = c.[:^^C::i:]; // expected-error {{not derived from}}
static union { int m; };
constexpr auto r = ^^m;
auto p = &[:r:]; // expected-error {{cannot form a pointer-to-member}}
} // namespace anon_union_member_slice
// ===========
// idempotency
// ===========
namespace idempotency {
int x;
void fn();
struct S {
int x;
static constexpr int s_x = 11;
void fn();
static void s_fn();
};
enum Enum { A, B, C };
enum class EnumCls { A, B, C };
static_assert(&[:^^x:] == &x);
static_assert([:^^fn:] == fn);
static_assert(&[:^^S::x:] == &S::x);
static_assert(&[:^^S::s_x:] == &S::s_x);
static_assert(&[:^^S::fn:] == &S::fn);
static_assert([:^^S::s_fn:] == S::s_fn);
static_assert([:^^Enum::B:] == Enum::B);
static_assert([:^^EnumCls::B:] == EnumCls::B);
} // namespace idempotency
// ==============
// with_variables
// ==============
namespace with_variables {
consteval int fn() {
int x = 32;
constexpr auto rx = ^^x;
++[:rx:];
return x;
}
static_assert(fn() == 33);
} // namespace with_variables
// ==============
// with_functions
// ==============
namespace with_functions {
consteval int vanilla_fn() { return 42; }
consteval int with_default_arg(int a = 5) { return a; }
constexpr info r_vanilla_fn = ^^vanilla_fn;
constexpr info r_with_default_arg = ^^with_default_arg;
static_assert([:r_vanilla_fn:]() == 42);
static_assert([:r_with_default_arg:]() == 5);
static_assert([:r_with_default_arg:](11) == 11);
// With a dependent reflection.
template <info R> consteval int fn() { return [:R:](); }
static_assert(fn<r_vanilla_fn>() == 42);
static_assert(fn<r_with_default_arg>() == 5);
void runtime() {
(void) [:^^runtime:];
}
} // namespace with_functions
// ============================
// with_shadowed_function_names
// ============================
namespace with_shadowed_function_names {
struct B { consteval char fn() const { return 'B'; } };
struct D : B { consteval char fn() const { return 'D'; } };
constexpr auto rBfn = ^^B::fn;
constexpr auto rDfn = ^^D::fn;
constexpr D d;
constexpr auto rd = ^^d;
static_assert([:rd:].[:rBfn:]() == 'B');
static_assert([:rd:].[:rDfn:]() == 'D');
} // namespace with_shadowed_function_names
// ==================
// with_member_access
// ==================
// Check use of splices in member access expressions.
namespace with_member_access {
struct S {
int j;
int k;
consteval int getJ() const { return j; }
template <int N>
consteval int getJPlusN() const { return j + N; }
static consteval int eleven() { return 11; }
template <int N>
static consteval int constant() { return N; }
};
// Splicing dependent member references.
template <info RMem>
consteval int fn() {
S s = {11, 13};
return s.[:RMem:] + (&s)->[:RMem:];
}
static_assert(fn<^^S::j>() == 22);
static_assert(fn<^^S::k>() == 26);
// Splicing dependent member references with arrow syntax.
template <info RMem>
consteval int fn2() {
S s = {11, 13};
return s.*(&[:RMem:]) + (&s)->*(&[:RMem:]);
}
static_assert(fn<^^S::j>() == 22);
static_assert(fn<^^S::k>() == 26);
// Splicing member functions.
constexpr info r_getJ = ^^S::getJ;
static_assert(S{2, 4}.[:r_getJ:]() == 2);
// Splicing static member functions.
constexpr auto rEleven = ^^S::eleven;
static_assert([:rEleven:]() == 11);
// Splicing static member template function instantiation.
constexpr auto rConst14 = ^^S::constant<14>;
static_assert([:rConst14:]() == 14);
// Splicing member function template instanstiations.
constexpr auto rgetJPlus5 = ^^S::getJPlusN<5>;
static_assert(S{2, 4}.[:rgetJPlus5:]() == 7);
// Splicing member function template instantiations with spliced objects.
constexpr S instance {1, 4};
constexpr info rInstance = ^^instance;
static_assert([:rInstance:].[:rgetJPlus5:]() == 6);
static_assert((&[:rInstance:])->[:rgetJPlus5:]() == 6);
// Splicing dependent object in a member access expression.
template <info RObj>
consteval int fn3() {
return [:RObj:].k;
}
static_assert(fn3<^^instance>() == 4);
// Passing address of a spliced operand as an argument.
consteval int getMem(const S *s, int S::* mem) {
return s->*mem;
}
constexpr info rJ = ^^S::j;
static_assert(getMem(&instance, &[:rJ:]) == 1);
// Member access through a splice of a private member.
class WithPrivateBase : S {} d;
int dK = d.[:^^S::k:];
} // namespace with_member_access
// ===================
// with_entity_proxies
// ===================
namespace with_entity_proxies {
namespace NS {
namespace Inner {
consteval int fn() { return 42; }
template <auto V> consteval int tfn() { return V; }
} // namespace Inner
using Inner::fn;
using Inner::tfn;
} // namespace NS
// splice-expressions
static_assert([:^^NS::fn:]() == 42);
static_assert(template [:^^NS::tfn:]<4>() == 4);
// nested proxies
struct A { int m; };
struct B : A { using A::m; };
struct C : B { using B::m; };
static_assert(&[:^^C::m:] == &A::m);
} // namespace with_entity_proxies
// ===========================
// with_implicit_member_access
// ===========================
namespace with_implicit_member_access {
// Non-dependent case
struct S {
static constexpr int l = 3;
int k;
void fn2() { }
void fn() {
static_assert([:^^l:] == 3);
static_assert([:^^S:]::l == 3);
(void) this->[:^^k:];
(void) this->[:^^S:]::k;
this->[:^^fn2:]();
this->[:^^S:]::fn2();
}
};
// Dependent case
struct D {
static constexpr int l = 3;
int k;
void fn2() { }
template <typename T>
void fn() {
static_assert([:^^T:]::l == 3);
(void) this->[:^^T:]::l;
(void) this->[:^^T:]::fn2();
}
};
} // namespace with_implicit_member_access
// ======================
// with_overridden_memfns
// ======================
namespace with_overridden_memfns {
struct B { consteval virtual int fn() const { return 1; } };
struct D : B { consteval int fn() const override { return 2; } };
constexpr D d;
static_assert(d.[:^^D::fn:]() == 2);
static_assert(d.[:^^B::fn:]() == 2);
static_assert(d.[:^^B:]::fn() == 1);
// Splicing member as intermediate component of a member-access expression.
struct T { struct Inner { int v; } inner; };
constexpr auto r_inner = ^^T::inner;
constexpr T t = {{4}};
static_assert(t.[:r_inner:].v == 4);
} // namespace with_overridden_memfns
// ==========
// with_enums
// ==========
namespace with_enums {
enum Enum { A, B, C };
enum class EnumCls { A, B, C };
constexpr info rB = ^^B, rClsB = ^^EnumCls::B;
static_assert(rB != rClsB);
static_assert(int([:rB:]) == int([:rClsB:]));
static_assert(static_cast<Enum>([:rClsB:]) == B);
} // namespace with_enums
// ====================
// address_of_bit_field
// ====================
namespace address_of_bit_field {
struct S {
int x : 4, y : 4;
};
constexpr auto f() {
constexpr auto r = ^^S::y;
return &[:r:]; // expected-error {{address of bit-field requested}}
}
} // namespace address_of_bit_field
// =============
// colon_parsing
// =============
// Check that parsing correctly handles successions of ':'-characters.
namespace colon_parsing {
constexpr int x = 4;
constexpr auto rx = ^^x;
static_assert([:rx:] == 4);
constexpr unsigned Idx = 1;
constexpr int arr[] = {1, 2, 3};
static_assert(arr[::colon_parsing::Idx] == 2);
constexpr info rIdx = ^^Idx;
static_assert([:::colon_parsing::rIdx:] == 1);
struct WithIndexOperator {
bool operator[:>(int); // Test interaction with ':>'-digraph (i.e., ']').
};
} // namespace colon_parsing
// =======================================
// bb_clang_p2996_issue_22_regression_test
// =======================================
namespace bb_clang_p2996_issue_22_regression_test {
// Issue #22 invoked a crash involving CTAD in a double templated context.
// I wasn't able to find a more minimal reproduction of the crash, but am
// including this test to prevent regression.
template <decltype(^^::) FN>
struct Cls
{
template <typename RESULT, typename... Args>
struct Impl {
Impl(decltype(&[:FN:]));
};
template <typename RESULT, typename... Args>
Impl(RESULT (*)(Args...)) -> Impl<RESULT, Args...>;
};
void fn(int);
static_assert(^^decltype(Cls<^^fn>::Impl(&fn)) == ^^Cls<^^fn>::Impl<void, int>);
} // namespace bb_clang_p2996_issue_22_regression_test
// ========================================
// bb_clang_p2996_issue_131_regression_test
// ========================================
namespace bb_clang_p2996_issue_131_regression_test {
struct Y
{
int g(this Y const&, int, int);
};
static_assert(&Y::g == &[:^^Y::g:]);
} // namespace bb_clang_p2996_issue_131_regression_test
// ========================================
// bb_clang_p2996_issue_132_regression_test
// ========================================
namespace bb_clang_p2996_issue_132_regression_test {
template<typename>
void f()
{
auto func = []<auto Mem>() static {
return [: ^^[:Mem:] ::func :];
};
}
void g() {
f<int>();
}
} // namespace bb_clang_p2996_issue_132_regression_test