diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2892,6 +2892,11 @@ def err_unsupported_placeholder_constraint : Error< "constrained placeholder types other than simple 'auto' on non-type template " "parameters not supported yet">; +def err_unsupported_destructor_overloading : Error< + "overloading destructors is not supported yet in this version. Consult " + "'https://github.com/llvm/llvm-project/issues/45614' for updates">; +def note_unsupported_destructor_overloading_declaration : Note< + "destructor declared here.">; def err_template_different_requires_clause : Error< "requires clause differs in template redeclaration">; diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -6731,6 +6731,45 @@ return IssuedDiagnostic; } +namespace { + +/// We don't support C++20 constrained destructors yet, and we are unlikely to +/// do so in the near future. Until we do, we check here for multiple +/// declarations and report an error. We have to handle correctly the case of +/// merged declarations in modules and the case of invalid templated +/// destructors so this is a bit involved. +/// We also don't emit errors on OpenCL code because OpenCL destructors can +/// overload on address space (https://reviews.llvm.org/D64569). +void DiagnoseUnsupportedDestructorOverloading(Sema& S, const CXXRecordDecl* Record) { + ASTContext &Context = Record->getASTContext(); + QualType ClassType = Context.getTypeDeclType(Record); + + DeclarationName Name = Context.DeclarationNames.getCXXDestructorName( + Context.getCanonicalType(ClassType)); + + DeclContext::lookup_result R = Record->lookup(Name); + + if (!(R.empty() || R.isSingleResult()) && !Context.getLangOpts().OpenCL) { + bool HasNonTrivialOverloads = false; + auto FirstDecl = R.front(); + for (const auto &Decl : R) { + if (!Decl->isTemplateDecl() && !FirstDecl->isTemplateDecl() && + !Context.isSameEntity(Decl, FirstDecl)) { + HasNonTrivialOverloads = true; + } + } + if (HasNonTrivialOverloads) { + S.Diag(Record->getLocation(), + diag::err_unsupported_destructor_overloading); + for (const auto &Decl : R) { + S.Diag(Decl->getLocation(), + diag::note_unsupported_destructor_overloading_declaration); + } + } + } +} +} // namespace + /// Perform semantic checks on a class definition that has been /// completing, introducing implicitly-declared members, checking for /// abstract types, etc. @@ -6955,6 +6994,9 @@ CheckCompletedMemberFunction(M); }; + if (!inTemplateInstantiation()) + DiagnoseUnsupportedDestructorOverloading(*this, Record); + // Check the destructor before any other member function. We need to // determine whether it's trivial in order to determine whether the claas // type is a literal type, which is a prerequisite for determining whether diff --git a/clang/test/CXX/over/over.match/over.match.viable/p3.cpp b/clang/test/CXX/over/over.match/over.match.viable/p3.cpp --- a/clang/test/CXX/over/over.match/over.match.viable/p3.cpp +++ b/clang/test/CXX/over/over.match/over.match.viable/p3.cpp @@ -44,24 +44,26 @@ template struct S { + // expected-error@-1 {{overloading destructors is not supported}} void foo(int) requires false; void foo(A) requires true; S(A) requires false; S(double) requires true; ~S() requires false; // expected-note@-1 2{{because 'false' evaluated to false}} + // expected-note@-2 {{destructor declared here}} ~S() requires true; + // expected-note@-1 {{destructor declared here}} operator int() requires true; operator int() requires false; }; void bar() { + // Note - we have a hard error in this case until P0848 is implemented. WrapsStatics::foo(A{}); S{1.}.foo(A{}); // expected-error@-1{{invalid reference to function '~S': constraints not satisfied}} - // Note - this behavior w.r.t. constrained dtors is a consequence of current - // wording, which does not invoke overload resolution when a dtor is called. - // P0848 is set to address this issue. + S s = 1; // expected-error@-1{{invalid reference to function '~S': constraints not satisfied}} int a = s;