Skip to content

[clang] [Sema] Preserve nested name specifier prefix in MemberPointerType #118236

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1092,6 +1092,13 @@ sizeof...($TemplateParameter[[Elements]]);
$Field_dependentName[[waldo]];
}
};
)cpp",
// Pointer-to-member with nested-name-specifiers
R"cpp(
struct $Class_def[[Outer]] {
struct $Class_def[[Inner]] {};
};
using $Typedef_decl[[Alias]] = void ($Class[[Outer]]::$Class[[Inner]]:: *)();
)cpp"};
for (const auto &TestCase : TestCases)
// Mask off scope modifiers to keep the tests manageable.
Expand Down
20 changes: 14 additions & 6 deletions clang/lib/Sema/SemaType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5347,15 +5347,23 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,

case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate:
ClsType = QualType(NNS->getAsType(), 0);
const Type *NNSType = NNS->getAsType();
ClsType = QualType(NNSType, 0);
// Note: if the NNS has a prefix and ClsType is a nondependent
// TemplateSpecializationType, then the NNS prefix is NOT included
// in ClsType; hence we wrap ClsType into an ElaboratedType.
// NOTE: in particular, no wrap occurs if ClsType already is an
// Elaborated, DependentName, or DependentTemplateSpecialization.
if (isa<TemplateSpecializationType>(NNS->getAsType()))
// TemplateSpecializationType or a RecordType, then the NNS prefix is
// NOT included in ClsType; hence we wrap ClsType into an
// ElaboratedType. NOTE: in particular, no wrap occurs if ClsType
// already is an Elaborated, DependentName, or
// DependentTemplateSpecialization.
if (isa<DependentTemplateSpecializationType>(NNSType)) {
// FIXME: Rebuild DependentTemplateSpecializationType, adding the
// Prefix.
} else if (isa<TemplateSpecializationType, RecordType>(NNSType)) {
// Either the dependent case (TemplateSpecializationType), or the
// non-dependent one (RecordType).
ClsType = Context.getElaboratedType(ElaboratedTypeKeyword::None,
NNSPrefix, ClsType);
}
break;
}
} else {
Expand Down
42 changes: 30 additions & 12 deletions clang/test/AST/ast-dump-types-json.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -248,15 +248,24 @@ using ::TestUsingShadowDeclType;
// CHECK-NEXT: "inner": [
// CHECK-NEXT: {
// CHECK-NEXT: "id": "0x{{.*}}",
// CHECK-NEXT: "kind": "RecordType",
// CHECK-NEXT: "kind": "ElaboratedType",
// CHECK-NEXT: "type": {
// CHECK-NEXT: "qualType": "T"
// CHECK-NEXT: },
// CHECK-NEXT: "decl": {
// CHECK-NEXT: "id": "0x{{.*}}",
// CHECK-NEXT: "kind": "CXXRecordDecl",
// CHECK-NEXT: "name": "T"
// CHECK-NEXT: }
// CHECK-NEXT: "inner": [
// CHECK-NEXT: {
// CHECK-NEXT: "id": "0x{{.*}}",
// CHECK-NEXT: "kind": "RecordType",
// CHECK-NEXT: "type": {
// CHECK-NEXT: "qualType": "T"
// CHECK-NEXT: },
// CHECK-NEXT: "decl": {
// CHECK-NEXT: "id": "0x{{.*}}",
// CHECK-NEXT: "kind": "CXXRecordDecl",
// CHECK-NEXT: "name": "T"
// CHECK-NEXT: }
// CHECK-NEXT: }
// CHECK-NEXT: ]
// CHECK-NEXT: },
// CHECK-NEXT: {
// CHECK-NEXT: "id": "0x{{.*}}",
Expand Down Expand Up @@ -325,15 +334,24 @@ using ::TestUsingShadowDeclType;
// CHECK-NEXT: "inner": [
// CHECK-NEXT: {
// CHECK-NEXT: "id": "0x{{.*}}",
// CHECK-NEXT: "kind": "RecordType",
// CHECK-NEXT: "kind": "ElaboratedType",
// CHECK-NEXT: "type": {
// CHECK-NEXT: "qualType": "T"
// CHECK-NEXT: },
// CHECK-NEXT: "decl": {
// CHECK-NEXT: "id": "0x{{.*}}",
// CHECK-NEXT: "kind": "CXXRecordDecl",
// CHECK-NEXT: "name": "T"
// CHECK-NEXT: }
// CHECK-NEXT: "inner": [
// CHECK-NEXT: {
// CHECK-NEXT: "id": "0x{{.*}}",
// CHECK-NEXT: "kind": "RecordType",
// CHECK-NEXT: "type": {
// CHECK-NEXT: "qualType": "T"
// CHECK-NEXT: },
// CHECK-NEXT: "decl": {
// CHECK-NEXT: "id": "0x{{.*}}",
// CHECK-NEXT: "kind": "CXXRecordDecl",
// CHECK-NEXT: "name": "T"
// CHECK-NEXT: }
// CHECK-NEXT: }
// CHECK-NEXT: ]
// CHECK-NEXT: },
// CHECK-NEXT: {
// CHECK-NEXT: "id": "0x{{.*}}",
Expand Down
16 changes: 8 additions & 8 deletions clang/test/CXX/conv/conv.mem/p4.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ namespace test0 {
namespace test1 {
struct Derived : private Base {}; // expected-note 2 {{declared private here}}
void test() {
int (Derived::*d) = data_ptr; // expected-error {{cannot cast private base class 'Base' to 'test1::Derived'}}
int (Derived::*m)() = method_ptr; // expected-error {{cannot cast private base class 'Base' to 'test1::Derived'}}
int (Derived::*d) = data_ptr; // expected-error {{cannot cast private base class 'Base' to 'Derived'}}
int (Derived::*m)() = method_ptr; // expected-error {{cannot cast private base class 'Base' to 'Derived'}}
}
};

Expand All @@ -30,17 +30,17 @@ namespace test2 {
struct B : Base {};
struct Derived : A, B {};
void test() {
int (Derived::*d) = data_ptr; // expected-error {{ambiguous conversion from pointer to member of base class 'Base' to pointer to member of derived class 'test2::Derived':}}
int (Derived::*m)() = method_ptr; // expected-error {{ambiguous conversion from pointer to member of base class 'Base' to pointer to member of derived class 'test2::Derived':}}
int (Derived::*d) = data_ptr; // expected-error {{ambiguous conversion from pointer to member of base class 'Base' to pointer to member of derived class 'Derived':}}
int (Derived::*m)() = method_ptr; // expected-error {{ambiguous conversion from pointer to member of base class 'Base' to pointer to member of derived class 'Derived':}}
}
}

// Can't be virtual.
namespace test3 {
struct Derived : virtual Base {};
void test() {
int (Derived::*d) = data_ptr; // expected-error {{conversion from pointer to member of class 'Base' to pointer to member of class 'test3::Derived' via virtual base 'Base' is not allowed}}
int (Derived::*m)() = method_ptr; // expected-error {{conversion from pointer to member of class 'Base' to pointer to member of class 'test3::Derived' via virtual base 'Base' is not allowed}}
int (Derived::*d) = data_ptr; // expected-error {{conversion from pointer to member of class 'Base' to pointer to member of class 'Derived' via virtual base 'Base' is not allowed}}
int (Derived::*m)() = method_ptr; // expected-error {{conversion from pointer to member of class 'Base' to pointer to member of class 'Derived' via virtual base 'Base' is not allowed}}
}
}

Expand All @@ -49,8 +49,8 @@ namespace test4 {
struct A : Base {};
struct Derived : Base, virtual A {}; // expected-warning {{direct base 'Base' is inaccessible due to ambiguity:\n struct test4::Derived -> Base\n struct test4::Derived -> A -> Base}}
void test() {
int (Derived::*d) = data_ptr; // expected-error {{ambiguous conversion from pointer to member of base class 'Base' to pointer to member of derived class 'test4::Derived':}}
int (Derived::*m)() = method_ptr; // expected-error {{ambiguous conversion from pointer to member of base class 'Base' to pointer to member of derived class 'test4::Derived':}}
int (Derived::*d) = data_ptr; // expected-error {{ambiguous conversion from pointer to member of base class 'Base' to pointer to member of derived class 'Derived':}}
int (Derived::*m)() = method_ptr; // expected-error {{ambiguous conversion from pointer to member of base class 'Base' to pointer to member of derived class 'Derived':}}
}
}

Expand Down
12 changes: 6 additions & 6 deletions clang/test/CXX/drs/cwg0xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -858,7 +858,7 @@ namespace cwg54 { // cwg54: 2.8
// expected-error@-1 {{cannot cast 'struct B' to its private base class 'A'}}
// expected-note@#cwg54-B {{declared private here}}
int A::*smab = static_cast<int A::*>(&B::b);
// expected-error@-1 {{cannot cast 'cwg54::B' to its private base class 'cwg54::A'}}
// expected-error@-1 {{cannot cast 'cwg54::B' to its private base class 'A'}}
// expected-note@#cwg54-B {{declared private here}}
B &sba = static_cast<B&>(a);
// expected-error@-1 {{cannot cast private base class 'cwg54::A' to 'cwg54::B'}}
Expand All @@ -867,19 +867,19 @@ namespace cwg54 { // cwg54: 2.8
// expected-error@-1 {{cannot cast private base class 'cwg54::A' to 'cwg54::B'}}
// expected-note@#cwg54-B {{declared private here}}
int B::*smba = static_cast<int B::*>(&A::a);
// expected-error@-1 {{cannot cast private base class 'cwg54::A' to 'cwg54::B'}}
// expected-error@-1 {{cannot cast private base class 'cwg54::A' to 'B'}}
// expected-note@#cwg54-B {{declared private here}}

V &svb = static_cast<V&>(b);
V *spvb = static_cast<V*>(&b);
int V::*smvb = static_cast<int V::*>(&B::b);
// expected-error@-1 {{conversion from pointer to member of class 'cwg54::B' to pointer to member of class 'cwg54::V' via virtual base 'cwg54::V' is not allowed}}
// expected-error@-1 {{conversion from pointer to member of class 'cwg54::B' to pointer to member of class 'V' via virtual base 'cwg54::V' is not allowed}}
B &sbv = static_cast<B&>(v);
// expected-error@-1 {{cannot cast 'struct V' to 'B &' via virtual base 'cwg54::V'}}
B *spbv = static_cast<B*>(&v);
// expected-error@-1 {{cannot cast 'cwg54::V *' to 'B *' via virtual base 'cwg54::V'}}
int B::*smbv = static_cast<int B::*>(&V::v);
// expected-error@-1 {{conversion from pointer to member of class 'cwg54::V' to pointer to member of class 'cwg54::B' via virtual base 'cwg54::V' is not allowed}}
// expected-error@-1 {{conversion from pointer to member of class 'cwg54::V' to pointer to member of class 'B' via virtual base 'cwg54::V' is not allowed}}

A &cab = (A&)(b);
A *cpab = (A*)(&b);
Expand All @@ -891,13 +891,13 @@ namespace cwg54 { // cwg54: 2.8
V &cvb = (V&)(b);
V *cpvb = (V*)(&b);
int V::*cmvb = (int V::*)(&B::b);
// expected-error@-1 {{conversion from pointer to member of class 'cwg54::B' to pointer to member of class 'cwg54::V' via virtual base 'cwg54::V' is not allowed}}
// expected-error@-1 {{conversion from pointer to member of class 'cwg54::B' to pointer to member of class 'V' via virtual base 'cwg54::V' is not allowed}}
B &cbv = (B&)(v);
// expected-error@-1 {{cannot cast 'struct V' to 'B &' via virtual base 'cwg54::V'}}
B *cpbv = (B*)(&v);
// expected-error@-1 {{cannot cast 'cwg54::V *' to 'B *' via virtual base 'cwg54::V'}}
int B::*cmbv = (int B::*)(&V::v);
// expected-error@-1 {{conversion from pointer to member of class 'cwg54::V' to pointer to member of class 'cwg54::B' via virtual base 'cwg54::V' is not allowed}}
// expected-error@-1 {{conversion from pointer to member of class 'cwg54::V' to pointer to member of class 'B' via virtual base 'cwg54::V' is not allowed}}
}

namespace cwg55 { // cwg55: yes
Expand Down
2 changes: 1 addition & 1 deletion clang/test/CXX/drs/cwg13xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ namespace cwg1330 { // cwg1330: 4 c++11
// since-cxx17-note@-2 {{use 'noexcept(false)' instead}}
void (A::*af2)() throw() = &A::f;
// cxx98-14-error@-1 {{target exception specification is not superset of source}}
// since-cxx17-error@-2 {{cannot initialize a variable of type 'void (cwg1330::A::*)() throw()' with an rvalue of type 'void (cwg1330::A::*)() throw(T)': different exception specifications}}
// since-cxx17-error@-2 {{cannot initialize a variable of type 'void (A::*)() throw()' with an rvalue of type 'void (cwg1330::A::*)() throw(T)': different exception specifications}}

#if __cplusplus >= 201103L
static_assert(noexcept(A().g()), "");
Expand Down
28 changes: 14 additions & 14 deletions clang/test/CXX/drs/cwg3xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -537,9 +537,9 @@ namespace cwg330 { // cwg330: 7
void f(A *a) {
(void) reinterpret_cast<B1*>(a);
(void) reinterpret_cast<B2*>(a);
// expected-error@-1 {{ISO C++ does not allow reinterpret_cast from 'A *' (aka 'const volatile int (*)[1][2][3]') to 'B2 *' (aka 'int *const cwg330::swift_17882::X::***') because it casts away qualifiers, even though the source and destination types are unrelated}}
// expected-error@-1 {{ISO C++ does not allow reinterpret_cast from 'A *' (aka 'const volatile int (*)[1][2][3]') to 'B2 *' (aka 'int *const X::***') because it casts away qualifiers, even though the source and destination types are unrelated}}
(void) reinterpret_cast<B3*>(a);
// expected-error@-1 {{ISO C++ does not allow reinterpret_cast from 'A *' (aka 'const volatile int (*)[1][2][3]') to 'B3 *' (aka 'int *cwg330::swift_17882::X::*volatile **') because it casts away qualifiers, even though the source and destination types are unrelated}}
// expected-error@-1 {{ISO C++ does not allow reinterpret_cast from 'A *' (aka 'const volatile int (*)[1][2][3]') to 'B3 *' (aka 'int *X::*volatile **') because it casts away qualifiers, even though the source and destination types are unrelated}}
(void) reinterpret_cast<B4*>(a);
}
}
Expand Down Expand Up @@ -971,9 +971,9 @@ namespace cwg354 { // cwg354: yes c++11
ptr<(int S::*)0> p3; // #cwg354-p3
// cxx98-error@#cwg354-p3 {{non-type template argument does not refer to any declaration}}
// cxx98-note@#cwg354-ptr {{template parameter is declared here}}
// cxx11-14-error@#cwg354-p3 {{null non-type template argument of type 'int cwg354::S::*' does not match template parameter of type 'int *'}}
// cxx11-14-error@#cwg354-p3 {{null non-type template argument of type 'int S::*' does not match template parameter of type 'int *'}}
// cxx11-14-note@#cwg354-ptr {{template parameter is declared here}}
// since-cxx17-error@#cwg354-p3 {{value of type 'int cwg354::S::*' is not implicitly convertible to 'int *'}}
// since-cxx17-error@#cwg354-p3 {{value of type 'int S::*' is not implicitly convertible to 'int *'}}

template<int*> int both(); // #cwg354-both-int-ptr
template<int> int both(); // #cwg354-both-int
Expand All @@ -985,25 +985,25 @@ namespace cwg354 { // cwg354: yes c++11

template<int S::*> struct ptr_mem {}; // #cwg354-ptr_mem
ptr_mem<0> m0; // #cwg354-m0
// cxx98-error@#cwg354-m0 {{non-type template argument of type 'int' cannot be converted to a value of type 'int cwg354::S::*'}}
// cxx98-error@#cwg354-m0 {{non-type template argument of type 'int' cannot be converted to a value of type 'int S::*'}}
// cxx98-note@#cwg354-ptr_mem {{template parameter is declared here}}
// cxx11-14-error@#cwg354-m0 {{null non-type template argument must be cast to template parameter type 'int cwg354::S::*'}}
// cxx11-14-error@#cwg354-m0 {{null non-type template argument must be cast to template parameter type 'int S::*'}}
// cxx11-14-note@#cwg354-ptr_mem {{template parameter is declared here}}
// since-cxx17-error@#cwg354-m0 {{conversion from 'int' to 'int cwg354::S::*' is not allowed in a converted constant expression}}
// since-cxx17-error@#cwg354-m0 {{conversion from 'int' to 'int S::*' is not allowed in a converted constant expression}}
ptr_mem<(int S::*)0> m1;
// cxx98-error@-1 {{non-type template argument is not a pointer to member constant}}
ptr_mem<(float S::*)0> m2; // #cwg354-m2
// cxx98-error@#cwg354-m2 {{non-type template argument of type 'float cwg354::S::*' cannot be converted to a value of type 'int cwg354::S::*'}}
// cxx98-error@#cwg354-m2 {{non-type template argument of type 'float S::*' cannot be converted to a value of type 'int S::*'}}
// cxx98-note@#cwg354-ptr_mem {{template parameter is declared here}}
// cxx11-14-error@#cwg354-m2 {{null non-type template argument of type 'float cwg354::S::*' does not match template parameter of type 'int cwg354::S::*'}}
// cxx11-14-error@#cwg354-m2 {{null non-type template argument of type 'float S::*' does not match template parameter of type 'int S::*'}}
// cxx11-14-note@#cwg354-ptr_mem {{template parameter is declared here}}
// since-cxx17-error@#cwg354-m2 {{value of type 'float cwg354::S::*' is not implicitly convertible to 'int cwg354::S::*'}}
// since-cxx17-error@#cwg354-m2 {{value of type 'float S::*' is not implicitly convertible to 'int S::*'}}
ptr_mem<(int *)0> m3; // #cwg354-m3
// cxx98-error@#cwg354-m3 {{non-type template argument of type 'int *' cannot be converted to a value of type 'int cwg354::S::*'}}
// cxx98-error@#cwg354-m3 {{non-type template argument of type 'int *' cannot be converted to a value of type 'int S::*'}}
// cxx98-note@#cwg354-ptr_mem {{template parameter is declared here}}
// cxx11-14-error@#cwg354-m3 {{null non-type template argument of type 'int *' does not match template parameter of type 'int cwg354::S::*'}}
// cxx11-14-error@#cwg354-m3 {{null non-type template argument of type 'int *' does not match template parameter of type 'int S::*'}}
// cxx11-14-note@#cwg354-ptr_mem {{template parameter is declared here}}
// since-cxx17-error@#cwg354-m3 {{value of type 'int *' is not implicitly convertible to 'int cwg354::S::*'}}
// since-cxx17-error@#cwg354-m3 {{value of type 'int *' is not implicitly convertible to 'int S::*'}}
}

struct cwg355_S; // cwg355: yes
Expand Down Expand Up @@ -1701,7 +1701,7 @@ namespace cwg395 { // cwg395: 3.0
}
} null1;
int (S::*p)() = null1;
// expected-error@-1 {{no viable conversion from 'struct null1_t' to 'int (cwg395::S::*)()'}}
// expected-error@-1 {{no viable conversion from 'struct null1_t' to 'int (S::*)()'}}
// expected-note@#cwg395-conv-func {{candidate template ignored: couldn't infer template argument 'T'}}

template <typename T> using id = T;
Expand Down
4 changes: 2 additions & 2 deletions clang/test/CXX/drs/cwg4xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1172,11 +1172,11 @@ namespace cwg480 { // cwg480: yes

int A::*a = &A::n;
int D::*b = a;
// expected-error@-1 {{conversion from pointer to member of class 'cwg480::A' to pointer to member of class 'cwg480::D' via virtual base 'cwg480::B' is not allowed}}
// expected-error@-1 {{conversion from pointer to member of class 'A' to pointer to member of class 'D' via virtual base 'cwg480::B' is not allowed}}

extern int D::*c;
int A::*d = static_cast<int A::*>(c);
// expected-error@-1 {{conversion from pointer to member of class 'cwg480::D' to pointer to member of class 'cwg480::A' via virtual base 'cwg480::B' is not allowed}}
// expected-error@-1 {{conversion from pointer to member of class 'cwg480::D' to pointer to member of class 'A' via virtual base 'cwg480::B' is not allowed}}

D *e;
A *f = e;
Expand Down
2 changes: 1 addition & 1 deletion clang/test/CXX/drs/cwg5xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ namespace cwg522 { // cwg522: yes
b2(am);
b2a(am);
// expected-error@-1 {{no matching function for call to 'b2a'}}
// expected-note@#cwg522-b2a {{candidate template ignored: deduced type 'volatile int *cwg522::S::*const *' of 1st parameter does not match adjusted type 'int *cwg522::S::**' of argument}}
// expected-note@#cwg522-b2a {{candidate template ignored: deduced type 'volatile int *S::*const *' of 1st parameter does not match adjusted type 'int *S::**' of argument}}
b3(d);
b3(cd);
}
Expand Down
2 changes: 1 addition & 1 deletion clang/test/CXX/expr/expr.unary/expr.unary.op/p4.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace test0 {
template<typename T> void g(T);

void test() {
foo(&g<int>); // expected-error-re {{cannot form member pointer of type 'void (test0::A::*)(int){{( __attribute__\(\(thiscall\)\))?}}' without '&' and class name}}
foo(&g<int>); // expected-error-re {{cannot form member pointer of type 'void (A::*)(int){{( __attribute__\(\(thiscall\)\))?}}' without '&' and class name}}
}
};
}
Expand Down
Loading
Loading