390 lines
10 KiB
C++
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
|