mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-27 02:06:06 +00:00

CallExpr::getType() isn't enough here in some cases, we need to use CallExpr::getCallReturnType().
252 lines
6.9 KiB
C++
252 lines
6.9 KiB
C++
// RUN: %clang_cc1 -std=c++14 -fexperimental-new-constant-interpreter -verify=expected,both %s
|
|
// RUN: %clang_cc1 -std=c++23 -fexperimental-new-constant-interpreter -verify=expected,both %s
|
|
// RUN: %clang_cc1 -std=c++14 -verify=ref,both %s
|
|
// RUN: %clang_cc1 -std=c++23 -verify=ref,both %s
|
|
|
|
namespace MemberPointers {
|
|
struct A {
|
|
constexpr A(int n) : n(n) {}
|
|
int n;
|
|
constexpr int f() const { return n + 3; }
|
|
};
|
|
|
|
constexpr A a(7);
|
|
static_assert(A(5).*&A::n == 5, "");
|
|
static_assert((&a)->*&A::n == 7, "");
|
|
static_assert((A(8).*&A::f)() == 11, "");
|
|
static_assert(((&a)->*&A::f)() == 10, "");
|
|
|
|
struct B : A {
|
|
constexpr B(int n, int m) : A(n), m(m) {}
|
|
int m;
|
|
constexpr int g() const { return n + m + 1; }
|
|
};
|
|
constexpr B b(9, 13);
|
|
static_assert(B(4, 11).*&A::n == 4, "");
|
|
static_assert(B(4, 11).*&B::m == 11, "");
|
|
static_assert(B(4, 11).m == 11, "");
|
|
static_assert(B(4, 11).*(int(A::*))&B::m == 11, "");
|
|
static_assert(B(4, 11).*&B::m == 11, "");
|
|
static_assert((&b)->*&A::n == 9, "");
|
|
static_assert((&b)->*&B::m == 13, "");
|
|
static_assert((&b)->*(int(A::*))&B::m == 13, "");
|
|
static_assert((B(4, 11).*&A::f)() == 7, "");
|
|
static_assert((B(4, 11).*&B::g)() == 16, "");
|
|
|
|
static_assert((B(4, 11).*(int(A::*)() const)&B::g)() == 16, "");
|
|
|
|
static_assert(((&b)->*&A::f)() == 12, "");
|
|
static_assert(((&b)->*&B::g)() == 23, "");
|
|
static_assert(((&b)->*(int(A::*)()const)&B::g)() == 23, "");
|
|
|
|
|
|
struct S {
|
|
constexpr S(int m, int n, int (S::*pf)() const, int S::*pn) :
|
|
m(m), n(n), pf(pf), pn(pn) {}
|
|
constexpr S() : m(), n(), pf(&S::f), pn(&S::n) {}
|
|
|
|
constexpr int f() const { return this->*pn; }
|
|
virtual int g() const;
|
|
|
|
int m, n;
|
|
int (S::*pf)() const;
|
|
int S::*pn;
|
|
};
|
|
|
|
constexpr int S::*pm = &S::m;
|
|
constexpr int S::*pn = &S::n;
|
|
|
|
constexpr int (S::*pf)() const = &S::f;
|
|
constexpr int (S::*pg)() const = &S::g;
|
|
|
|
constexpr S s(2, 5, &S::f, &S::m);
|
|
|
|
static_assert((s.*&S::f)() == 2, "");
|
|
static_assert((s.*s.pf)() == 2, "");
|
|
|
|
static_assert(pf == &S::f, "");
|
|
|
|
static_assert(pf == s.*&S::pf, "");
|
|
|
|
static_assert(pm == &S::m, "");
|
|
static_assert(pm != pn, "");
|
|
static_assert(s.pn != pn, "");
|
|
static_assert(s.pn == pm, "");
|
|
static_assert(pg != nullptr, "");
|
|
static_assert(pf != nullptr, "");
|
|
static_assert((int S::*)nullptr == nullptr, "");
|
|
static_assert(pg == pg, ""); // both-error {{constant expression}} \
|
|
// both-note {{comparison of pointer to virtual member function 'g' has unspecified value}}
|
|
static_assert(pf != pg, ""); // both-error {{constant expression}} \
|
|
// both-note {{comparison of pointer to virtual member function 'g' has unspecified value}}
|
|
|
|
template<int n> struct T : T<n-1> { const int X = n;};
|
|
template<> struct T<0> { int n; char k;};
|
|
template<> struct T<30> : T<29> { int m; };
|
|
|
|
T<17> t17;
|
|
T<30> t30;
|
|
|
|
constexpr int (T<15>::*deepm) = (int(T<10>::*))&T<30>::m;
|
|
constexpr int (T<10>::*deepn) = &T<0>::n;
|
|
constexpr char (T<10>::*deepk) = &T<0>::k;
|
|
|
|
static_assert(&(t17.*deepn) == &t17.n, "");
|
|
static_assert(&(t17.*deepk) == &t17.k, "");
|
|
static_assert(deepn == &T<2>::n, "");
|
|
|
|
constexpr int *pgood = &(t30.*deepm);
|
|
constexpr int *pbad = &(t17.*deepm); // both-error {{constant expression}}
|
|
static_assert(&(t30.*deepm) == &t30.m, "");
|
|
|
|
static_assert(deepm == &T<50>::m, "");
|
|
static_assert(deepm != deepn, "");
|
|
|
|
constexpr T<5> *p17_5 = &t17;
|
|
constexpr T<13> *p17_13 = (T<13>*)p17_5;
|
|
constexpr T<23> *p17_23 = (T<23>*)p17_13; // both-error {{constant expression}} \
|
|
// both-note {{cannot cast object of dynamic type 'T<17>' to type 'T<23>'}}
|
|
constexpr T<18> *p17_18 = (T<18>*)p17_13; // both-error {{constant expression}} \
|
|
// both-note {{cannot cast object of dynamic type 'T<17>' to type 'T<18>'}}
|
|
static_assert(&(p17_5->*(int(T<0>::*))deepn) == &t17.n, "");
|
|
static_assert(&(p17_5->*(int(T<0>::*))deepn), "");
|
|
|
|
|
|
static_assert(&(p17_13->*deepn) == &t17.n, "");
|
|
constexpr int *pbad2 = &(p17_13->*(int(T<9>::*))deepm); // both-error {{constant expression}}
|
|
|
|
constexpr T<5> *p30_5 = &t30;
|
|
constexpr T<23> *p30_23 = (T<23>*)p30_5;
|
|
constexpr T<13> *p30_13 = p30_23;
|
|
static_assert(&(p30_13->*deepn) == &t30.n, "");
|
|
static_assert(&(p30_23->*deepn) == &t30.n, "");
|
|
static_assert(&(p30_5->*(int(T<3>::*))deepn) == &t30.n, "");
|
|
|
|
static_assert(&(p30_5->*(int(T<2>::*))deepm) == &t30.m, "");
|
|
static_assert(&(((T<17>*)p30_13)->*deepm) == &t30.m, "");
|
|
static_assert(&(p30_23->*deepm) == &t30.m, "");
|
|
|
|
|
|
/// Added tests not from constant-expression-cxx11.cpp
|
|
static_assert(pm, "");
|
|
static_assert(!((int S::*)nullptr), "");
|
|
constexpr int S::*pk = nullptr;
|
|
static_assert(!pk, "");
|
|
}
|
|
|
|
namespace test3 {
|
|
struct nsCSSRect {
|
|
};
|
|
static int nsCSSRect::* sides;
|
|
nsCSSRect dimenX;
|
|
void ParseBoxCornerRadii(int y) {
|
|
switch (y) {
|
|
}
|
|
int& x = dimenX.*sides;
|
|
}
|
|
}
|
|
|
|
void foo() {
|
|
class X;
|
|
void (X::*d) ();
|
|
d = nullptr; /// This calls in the constant interpreter.
|
|
}
|
|
|
|
namespace {
|
|
struct A { int n; };
|
|
struct B { int n; };
|
|
struct C : A, B {};
|
|
struct D { double d; C c; };
|
|
const int &&u = static_cast<B&&>(0, ((D&&)D{}).*&D::c).n; // both-warning {{left operand of comma operator has no effect}}
|
|
}
|
|
|
|
/// From SemaTemplate/instantiate-member-pointers.cpp
|
|
namespace {
|
|
struct Y {
|
|
int x;
|
|
};
|
|
|
|
template<typename T, typename Class, T Class::*Ptr>
|
|
struct X3 {
|
|
X3<T, Class, Ptr> &operator=(const T& value) {
|
|
return *this;
|
|
}
|
|
};
|
|
|
|
typedef int Y::*IntMember;
|
|
template<IntMember Member>
|
|
struct X4 {
|
|
X3<int, Y, Member> member;
|
|
int &getMember(Y& y) { return y.*Member; }
|
|
};
|
|
|
|
int &get_X4(X4<&Y::x> x4, Y& y) {
|
|
return x4.getMember(y);
|
|
}
|
|
}
|
|
|
|
/// From test/CXX/basic/basic.def.odr/p2.cpp
|
|
namespace {
|
|
void use(int);
|
|
struct S { int x; int f() const; };
|
|
constexpr S *ps = nullptr;
|
|
S *const &psr = ps;
|
|
|
|
void test() {
|
|
use(ps->*&S::x);
|
|
use(psr->*&S::x);
|
|
}
|
|
}
|
|
|
|
namespace MemPtrTemporary {
|
|
struct A {
|
|
constexpr int f() const { return 5; }
|
|
};
|
|
|
|
constexpr int apply(const A &a, int (A::*ff)() const) {
|
|
return (a.*ff)();
|
|
}
|
|
|
|
static_assert(apply(A(), &A::f) == 5, "");
|
|
}
|
|
|
|
namespace IndirectFields {
|
|
struct I { union { struct { int a, b; }; }; };
|
|
|
|
template <typename T, int T::*F>
|
|
constexpr int ReadField(const T &o) {
|
|
return F ? o.*F : 0;
|
|
}
|
|
void ReadFields() {
|
|
I i;
|
|
ReadField<I, &I::a>(i);
|
|
ReadField<I, &I::b>(i);
|
|
}
|
|
|
|
constexpr I i{12};
|
|
static_assert(ReadField<I, &I::a>(i) == 12, "");
|
|
}
|
|
|
|
namespace CallExprTypeMismatch {
|
|
/// The call expression's getType() returns just S, not S&.
|
|
struct S {
|
|
constexpr S(int i_) : i(i_) {}
|
|
constexpr const S& identity() const { return *this; }
|
|
int i;
|
|
};
|
|
|
|
template<typename T, typename U>
|
|
constexpr void Call(T t, U u) {
|
|
((&u)->*t)();
|
|
}
|
|
|
|
constexpr bool test() {
|
|
const S s{12};
|
|
|
|
Call(&S::identity, s);
|
|
|
|
return true;
|
|
}
|
|
static_assert(test(), "");
|
|
}
|