if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(NewFD)) {
CheckConstructor(Constructor);
} else if (CXXDestructorDecl *Destructor =
- dyn_cast<CXXDestructorDecl>(NewFD)) {
- CXXRecordDecl *Record = Destructor->getParent();
- QualType ClassType = Context.getTypeDeclType(Record);
-
- DeclarationName Name = Context.DeclarationNames.getCXXDestructorName(
- Context.getCanonicalType(ClassType));
- if (NewFD->getDeclName() != Name) {
- Diag(NewFD->getLocation(), diag::err_destructor_name);
- NewFD->setInvalidDecl();
- return Redeclaration;
+ dyn_cast<CXXDestructorDecl>(NewFD)) {
+ // We check here for invalid destructor names.
+ // If we have a friend destructor declaration that is dependent, we can't
+ // diagnose right away because cases like this are still valid:
+ // template <class T> struct A { friend T::X::~Y(); };
+ // struct B { struct Y { ~Y(); }; using X = Y; };
+ // template struct A<B>;
+ if (NewFD->getFriendObjectKind() == Decl::FriendObjectKind::FOK_None ||
+ !Destructor->getThisType()->isDependentType()) {
+ CXXRecordDecl *Record = Destructor->getParent();
+ QualType ClassType = Context.getTypeDeclType(Record);
+
+ DeclarationName Name = Context.DeclarationNames.getCXXDestructorName(
+ Context.getCanonicalType(ClassType));
+ if (NewFD->getDeclName() != Name) {
+ Diag(NewFD->getLocation(), diag::err_destructor_name);
+ NewFD->setInvalidDecl();
+ return Redeclaration;
+ }
}
} else if (auto *Guide = dyn_cast<CXXDeductionGuideDecl>(NewFD)) {
if (auto *TD = Guide->getDescribedFunctionTemplate())
~B(); // expected-error {{expected the class name after '~' to name the enclosing class}}
};
+template <typename T>
+struct D {
+ friend T::S::~S();
+private:
+ static constexpr int secret = 42;
+};
+
+template <typename T>
+struct E {
+ friend T::S::~V();
+};
+
+struct BadInstantiation {
+ struct S {
+ struct V {};
+ };
+};
+
+struct GoodInstantiation {
+ struct V {
+ ~V();
+ };
+ using S = V;
+};
+
+// FIXME: We should diagnose this while instantiating.
+E<BadInstantiation> x;
+E<GoodInstantiation> y;
+
+struct Q {
+ struct S { ~S(); };
+};
+
+Q::S::~S() {
+ void foo(int);
+ foo(D<Q>::secret);
+}
+
+struct X {
+ ~X();
+};
+struct Y;
+
+struct Z1 {
+ friend X::~Y(); // expected-error {{expected the class name after '~' to name the enclosing class}}
+};
+
+template <class T>
+struct Z2 {
+ friend X::~Y(); // expected-error {{expected the class name after '~' to name the enclosing class}}
+};
+
}