mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-17 07:06:42 +00:00

Original PR: #130537 Originally reverted due to revert of dependent commit. Relanding with no changes. This changes the MemberPointerType representation to use a NestedNameSpecifier instead of a Type to represent the base class. Since the qualifiers are always parsed as nested names, there was an impedance mismatch when converting these back and forth into types, and this led to issues in preserving sugar. The nested names are indeed a better match for these, as the differences which a QualType can represent cannot be expressed syntatically, and they represent the use case more exactly, being either dependent or referring to a CXXRecord, unqualified. This patch also makes the MemberPointerType able to represent sugar for a {up/downcast}cast conversion of the base class, although for now the underlying type is canonical, as preserving the sugar up to that point requires further work. As usual, includes a few drive-by fixes in order to make use of the improvements.
76 lines
1.8 KiB
C++
76 lines
1.8 KiB
C++
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
|
|
struct Y {
|
|
int x;
|
|
};
|
|
|
|
template<typename T>
|
|
struct X1 {
|
|
int f(T* ptr, int T::*pm) {
|
|
// expected-error@-1 {{type 'int' cannot be used prior to '::' because it has no members}}
|
|
return ptr->*pm;
|
|
}
|
|
};
|
|
|
|
template struct X1<Y>;
|
|
template struct X1<int>; // expected-note{{instantiation}}
|
|
|
|
template<typename T, typename Class>
|
|
struct X2 {
|
|
T f(Class &obj, T Class::*pm) { // expected-error{{to a reference}} \
|
|
// expected-error{{member pointer to void}}
|
|
return obj.*pm;
|
|
}
|
|
};
|
|
|
|
template struct X2<int, Y>;
|
|
template struct X2<int&, Y>; // expected-note{{instantiation}}
|
|
template struct X2<const void, Y>; // expected-note{{instantiation}}
|
|
|
|
template<typename T, typename Class, T Class::*Ptr>
|
|
struct X3 {
|
|
X3<T, Class, Ptr> &operator=(const T& value) {
|
|
return *this;
|
|
}
|
|
};
|
|
|
|
X3<int, Y, &Y::x> x3;
|
|
|
|
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);
|
|
}
|
|
|
|
template<IntMember Member>
|
|
void accept_X4(X4<Member>);
|
|
|
|
void test_accept_X4(X4<&Y::x> x4) {
|
|
accept_X4(x4);
|
|
}
|
|
|
|
namespace ValueDepMemberPointer {
|
|
template <void (*)()> struct instantiate_function {};
|
|
template <typename T> struct S {
|
|
static void instantiate();
|
|
typedef instantiate_function<&S::instantiate> x; // expected-note{{instantiation}}
|
|
};
|
|
template <typename T> void S<T>::instantiate() {
|
|
int a[(int)sizeof(T)-42]; // expected-error{{array with a negative size}}
|
|
}
|
|
S<int> s;
|
|
}
|
|
|
|
namespace PR18192 {
|
|
struct A { struct { int n; }; };
|
|
template<int A::*> struct X {};
|
|
constexpr int A::*p = &A::n;
|
|
X<p> x; // expected-error{{not a pointer to member constant}}
|
|
}
|