[clang] [Clang] [C++26] Implement P2573R2: `= delete("should have a reason");` (PR #86526)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Mar 26 06:32:09 PDT 2024
https://github.com/Sirraide updated https://github.com/llvm/llvm-project/pull/86526
>From 98af47e8ccc633016c14b91c221f9f8fc620f068 Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Mon, 25 Mar 2024 14:46:52 +0100
Subject: [PATCH 1/8] [Clang] Parse `= delete("message")`
---
clang/include/clang/AST/Decl.h | 13 ++++++++
clang/include/clang/Parse/Parser.h | 1 +
clang/include/clang/Sema/Sema.h | 6 ++--
clang/lib/AST/Decl.cpp | 4 +--
clang/lib/AST/DeclPrinter.cpp | 9 +++--
clang/lib/AST/TextNodeDumper.cpp | 3 ++
clang/lib/Parse/ParseCXXInlineMethods.cpp | 24 +++++++++++++-
clang/lib/Parse/Parser.cpp | 4 ++-
clang/lib/Sema/SemaDeclCXX.cpp | 10 +++---
.../lib/Sema/SemaTemplateInstantiateDecl.cpp | 6 ++++
.../test/Parser/cxx2c-delete-with-message.cpp | 33 +++++++++++++++++++
11 files changed, 100 insertions(+), 13 deletions(-)
create mode 100644 clang/test/Parser/cxx2c-delete-with-message.cpp
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index a5879591f4c659..24f0394577e228 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -2013,6 +2013,12 @@ class FunctionDecl : public DeclaratorDecl,
DefaultedFunctionInfo *DefaultedInfo;
};
+ /// Message that indicates why this function was deleted.
+ ///
+ /// FIXME: Figure out where to actually put this; maybe in the
+ /// 'DefaultedInfo' above?
+ StringLiteral *DeletedMessage;
+
unsigned ODRHash;
/// End part of this FunctionDecl's source range.
@@ -2483,6 +2489,10 @@ class FunctionDecl : public DeclaratorDecl,
}
void setDeletedAsWritten(bool D = true) { FunctionDeclBits.IsDeleted = D; }
+ void setDeletedWithMessage(StringLiteral* Message) {
+ FunctionDeclBits.IsDeleted = true;
+ DeletedMessage = Message;
+ }
/// Determines whether this function is "main", which is the
/// entry point into an executable program.
@@ -2638,6 +2648,9 @@ class FunctionDecl : public DeclaratorDecl,
AC.push_back(TRC);
}
+ /// Get the message that indicates why this function was deleted.
+ StringLiteral *getDeletedMessage() const { return DeletedMessage; }
+
void setPreviousDeclaration(FunctionDecl * PrevDecl);
FunctionDecl *getCanonicalDecl() override;
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index 14df75180ef321..559e6416b7dfb3 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -1600,6 +1600,7 @@ class Parser : public CodeCompletionHandler {
const ParsedTemplateInfo &TemplateInfo,
const VirtSpecifiers &VS,
SourceLocation PureSpecLoc);
+ StringLiteral *ParseCXXDeletedFunctionMessage();
void ParseCXXNonStaticMemberInitializer(Decl *VarD);
void ParseLexedAttributes(ParsingClass &Class);
void ParseLexedAttributeList(LateParsedAttrList &LAs, Decl *D,
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 64de39acc72176..919f8f6b0a35a2 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -4926,10 +4926,12 @@ class Sema final {
SourceLocation EqualLoc);
void ActOnPureSpecifier(Decl *D, SourceLocation PureSpecLoc);
- void SetDeclDeleted(Decl *dcl, SourceLocation DelLoc);
+ void SetDeclDeleted(Decl *dcl, SourceLocation DelLoc,
+ StringLiteral *Message = nullptr);
void SetDeclDefaulted(Decl *dcl, SourceLocation DefaultLoc);
- void SetFunctionBodyKind(Decl *D, SourceLocation Loc, FnBodyKind BodyKind);
+ void SetFunctionBodyKind(Decl *D, SourceLocation Loc, FnBodyKind BodyKind,
+ StringLiteral *DeletedMessage = nullptr);
void ActOnStartTrailingRequiresClause(Scope *S, Declarator &D);
ExprResult ActOnFinishTrailingRequiresClause(ExprResult ConstraintExpr);
ExprResult ActOnRequiresClause(ExprResult ConstraintExpr);
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 95900afdd2c5d8..b5e61f0eceb6e4 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -3043,8 +3043,8 @@ FunctionDecl::FunctionDecl(Kind DK, ASTContext &C, DeclContext *DC,
Expr *TrailingRequiresClause)
: DeclaratorDecl(DK, DC, NameInfo.getLoc(), NameInfo.getName(), T, TInfo,
StartLoc),
- DeclContext(DK), redeclarable_base(C), Body(), ODRHash(0),
- EndRangeLoc(NameInfo.getEndLoc()), DNLoc(NameInfo.getInfo()) {
+ DeclContext(DK), redeclarable_base(C), Body(), DeletedMessage(nullptr),
+ ODRHash(0), EndRangeLoc(NameInfo.getEndLoc()), DNLoc(NameInfo.getInfo()) {
assert(T.isNull() || T->isFunctionType());
FunctionDeclBits.SClass = S;
FunctionDeclBits.IsInline = isInlineSpecified;
diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp
index b701581b2474a9..d04cdd5a10e033 100644
--- a/clang/lib/AST/DeclPrinter.cpp
+++ b/clang/lib/AST/DeclPrinter.cpp
@@ -873,9 +873,14 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
if (D->isPureVirtual())
Out << " = 0";
- else if (D->isDeletedAsWritten())
+ else if (D->isDeletedAsWritten()) {
Out << " = delete";
- else if (D->isExplicitlyDefaulted())
+ if (const auto *M = D->getDeletedMessage()) {
+ Out << "(";
+ M->outputString(Out);
+ Out << ")";
+ }
+ } else if (D->isExplicitlyDefaulted())
Out << " = default";
else if (D->doesThisDeclarationHaveABody()) {
if (!Policy.TerseOutput) {
diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp
index b683eb1edd8f13..4a2369330a35e7 100644
--- a/clang/lib/AST/TextNodeDumper.cpp
+++ b/clang/lib/AST/TextNodeDumper.cpp
@@ -1936,6 +1936,9 @@ void TextNodeDumper::VisitFunctionDecl(const FunctionDecl *D) {
if (D->isTrivial())
OS << " trivial";
+ if (const auto *M = D->getDeletedMessage())
+ AddChild("delete message", [=] { Visit(M); });
+
if (D->isIneligibleOrNotSelected())
OS << (isa<CXXDestructorDecl>(D) ? " not_selected" : " ineligible");
diff --git a/clang/lib/Parse/ParseCXXInlineMethods.cpp b/clang/lib/Parse/ParseCXXInlineMethods.cpp
index d790060c17c049..c551023a1e9dbc 100644
--- a/clang/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/clang/lib/Parse/ParseCXXInlineMethods.cpp
@@ -20,6 +20,27 @@
using namespace clang;
+/// Parse the optional ("message") part of a deleted-function-body.
+StringLiteral *Parser::ParseCXXDeletedFunctionMessage() {
+ if (!Tok.is(tok::l_paren)) return nullptr;
+ StringLiteral *Message = nullptr;
+ BalancedDelimiterTracker BT{*this, tok::l_paren};
+ BT.consumeOpen();
+
+ if (isTokenStringLiteral()) {
+ ExprResult Res = ParseUnevaluatedStringLiteralExpression();
+ if (Res.isUsable())
+ Message = Res.getAs<StringLiteral>();
+ } else {
+ Diag(Tok.getLocation(), diag::err_expected_string_literal)
+ << /*Source='in'*/ 0 << "'delete'";
+ SkipUntil(tok::r_paren, StopAtSemi | StopBeforeMatch);
+ }
+
+ BT.consumeClose();
+ return Message;
+}
+
/// ParseCXXInlineMethodDef - We parsed and verified that the specified
/// Declarator is a well formed C++ inline method definition. Now lex its body
/// and store its tokens for parsing after the C++ class is complete.
@@ -70,7 +91,8 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(
? diag::warn_cxx98_compat_defaulted_deleted_function
: diag::ext_defaulted_deleted_function)
<< 1 /* deleted */;
- Actions.SetDeclDeleted(FnD, KWLoc);
+ StringLiteral* Message = ParseCXXDeletedFunctionMessage();
+ Actions.SetDeclDeleted(FnD, KWLoc, Message);
Delete = true;
if (auto *DeclAsFunction = dyn_cast<FunctionDecl>(FnD)) {
DeclAsFunction->setRangeEnd(KWEndLoc);
diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index cc0e41ed221c4f..d6f2b9f448cd52 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -1404,6 +1404,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
// Parse function body eagerly if it is either '= delete;' or '= default;' as
// ActOnStartOfFunctionDef needs to know whether the function is deleted.
+ StringLiteral *DeletedMessage = nullptr;
Sema::FnBodyKind BodyKind = Sema::FnBodyKind::Other;
SourceLocation KWLoc;
if (TryConsumeToken(tok::equal)) {
@@ -1415,6 +1416,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
: diag::ext_defaulted_deleted_function)
<< 1 /* deleted */;
BodyKind = Sema::FnBodyKind::Delete;
+ DeletedMessage = ParseCXXDeletedFunctionMessage();
} else if (TryConsumeToken(tok::kw_default, KWLoc)) {
Diag(KWLoc, getLangOpts().CPlusPlus11
? diag::warn_cxx98_compat_defaulted_deleted_function
@@ -1473,7 +1475,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
D.getMutableDeclSpec().abort();
if (BodyKind != Sema::FnBodyKind::Other) {
- Actions.SetFunctionBodyKind(Res, KWLoc, BodyKind);
+ Actions.SetFunctionBodyKind(Res, KWLoc, BodyKind, DeletedMessage);
Stmt *GeneratedBody = Res ? Res->getBody() : nullptr;
Actions.ActOnFinishFunctionBody(Res, GeneratedBody, false);
return Res;
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index e258a4f7c89415..e6d653aedd061c 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -18108,7 +18108,7 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
return ND;
}
-void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) {
+void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc, StringLiteral *Message) {
AdjustDeclIfTemplate(Dcl);
FunctionDecl *Fn = dyn_cast_or_null<FunctionDecl>(Dcl);
@@ -18157,7 +18157,7 @@ void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) {
// C++11 [dcl.fct.def.delete]p4:
// A deleted function is implicitly inline.
Fn->setImplicitlyInline();
- Fn->setDeletedAsWritten();
+ Fn->setDeletedWithMessage(Message);
}
void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) {
@@ -18270,11 +18270,11 @@ void Sema::DiagnoseReturnInConstructorExceptionHandler(CXXTryStmt *TryBlock) {
}
}
-void Sema::SetFunctionBodyKind(Decl *D, SourceLocation Loc,
- FnBodyKind BodyKind) {
+void Sema::SetFunctionBodyKind(Decl *D, SourceLocation Loc, FnBodyKind BodyKind,
+ StringLiteral *DeletedMessage) {
switch (BodyKind) {
case FnBodyKind::Delete:
- SetDeclDeleted(D, Loc);
+ SetDeclDeleted(D, Loc, DeletedMessage);
break;
case FnBodyKind::Default:
SetDeclDefaulted(D, Loc);
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index dc972018e7b281..549ffd4b0b6df5 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -2202,6 +2202,9 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
if (D->isLocalExternDecl())
Function->setLocalExternDecl();
+ if (D->isDeletedAsWritten())
+ Function->setDeletedWithMessage(D->getDeletedMessage());
+
DeclContext *LexicalDC = Owner;
if (!isFriend && D->isOutOfLine() && !D->isLocalExternDecl()) {
assert(D->getDeclContext()->isFileContext());
@@ -2627,6 +2630,9 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
if (QualifierLoc)
Method->setQualifierInfo(QualifierLoc);
+ if (D->isDeletedAsWritten())
+ Method->setDeletedWithMessage(D->getDeletedMessage());
+
if (TemplateParams) {
// Our resulting instantiation is actually a function template, since we
// are substituting only the outer template parameters. For example, given
diff --git a/clang/test/Parser/cxx2c-delete-with-message.cpp b/clang/test/Parser/cxx2c-delete-with-message.cpp
new file mode 100644
index 00000000000000..67a4c944187d7f
--- /dev/null
+++ b/clang/test/Parser/cxx2c-delete-with-message.cpp
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -std=c++2c -fsyntax-only -verify %s
+
+struct S {
+ void a() = delete;
+ void b() = delete(; // expected-error {{expected string literal}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ void c() = delete(); // expected-error {{expected string literal}}
+ void d() = delete(42); // expected-error {{expected string literal}}
+ void e() = delete("foo"[0]); // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ void f() = delete("foo");
+
+ S() = delete("foo");
+ ~S() = delete("foo");
+ S(const S&) = delete("foo");
+ S(S&&) = delete("foo");
+ S& operator=(const S&) = delete("foo");
+ S& operator=(S&&) = delete("foo");
+};
+
+struct T {
+ T() = delete(); // expected-error {{expected string literal}}
+ ~T() = delete(); // expected-error {{expected string literal}}
+ T(const T&) = delete(); // expected-error {{expected string literal}}
+ T(T&&) = delete(); // expected-error {{expected string literal}}
+ T& operator=(const T&) = delete(); // expected-error {{expected string literal}}
+ T& operator=(T&&) = delete(); // expected-error {{expected string literal}}
+};
+
+void a() = delete;
+void b() = delete(; // expected-error {{expected string literal}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+void c() = delete(); // expected-error {{expected string literal}}
+void d() = delete(42); // expected-error {{expected string literal}}
+void e() = delete("foo"[0]); // expected-error {{expected ')'}} expected-note {{to match this '('}}
+void f() = delete("foo");
>From 5ffac609e2cd0a365632974a72f944ed7f1a3779 Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Mon, 25 Mar 2024 15:06:01 +0100
Subject: [PATCH 2/8] [Clang] Tentative serialisation
---
clang/lib/Serialization/ASTReaderDecl.cpp | 5 ++++
clang/lib/Serialization/ASTWriterDecl.cpp | 7 ++++++
.../ast-dump-cxx2c-delete-with-message.cpp | 23 +++++++++++++++++++
3 files changed, 35 insertions(+)
create mode 100644 clang/test/AST/ast-dump-cxx2c-delete-with-message.cpp
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index a22f760408c634..37bc61b9a63a34 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -1122,6 +1122,11 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
}
}
+ // FIXME: See ASTWriterDecl::VisitFunctionDecl.
+ if (FD->isDeletedAsWritten())
+ FD->setDeletedWithMessage(
+ cast_if_present<StringLiteral>(Record.readStmt()));
+
if (Existing)
mergeRedeclarable(FD, Existing, Redecl);
else if (auto Kind = FD->getTemplatedKind();
diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp
index 86f64bf2a24250..af7dbe916419eb 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -761,6 +761,13 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
}
}
+ // FIXME: Hack: We're out of bits in FunctionDeclBits, so always
+ // add this even though it's 0 in the vast majority of cases. We
+ // might really want to consider storing this in the DefaultedFunctionInfo
+ // instead.
+ if (D->isDeletedAsWritten())
+ Record.AddStmt(D->getDeletedMessage());
+
Record.push_back(D->param_size());
for (auto *P : D->parameters())
Record.AddDeclRef(P);
diff --git a/clang/test/AST/ast-dump-cxx2c-delete-with-message.cpp b/clang/test/AST/ast-dump-cxx2c-delete-with-message.cpp
new file mode 100644
index 00000000000000..ea16b97da23e40
--- /dev/null
+++ b/clang/test/AST/ast-dump-cxx2c-delete-with-message.cpp
@@ -0,0 +1,23 @@
+// Without serialization:
+// RUN: %clang_cc1 -ast-dump %s | FileCheck %s
+//
+// With serialization:
+// RUN: %clang_cc1 -emit-pch -o %t %s
+// RUN: %clang_cc1 -x c++ -include-pch %t -ast-dump-all /dev/null | FileCheck %s
+
+struct S {
+ // CHECK: CXXMethodDecl {{.*}} a 'void ()' delete
+ // CHECK-NEXT: delete message: StringLiteral {{.*}} "foo"
+ void a() = delete("foo");
+
+ // CHECK: FunctionTemplateDecl {{.*}} b
+ // CHECK-NEXT: TemplateTypeParmDecl
+ // CHECK-NEXT: CXXMethodDecl {{.*}} b 'void ()' delete
+ // CHECK-NEXT: delete message: StringLiteral {{.*}} "bar"
+ template <typename>
+ void b() = delete("bar");
+};
+
+// CHECK: FunctionDecl {{.*}} c 'void ()' delete
+// CHECK-NEXT: delete message: StringLiteral {{.*}} "baz"
+void c() = delete("baz");
>From 8dc5f8b4eaca3ea7a4c41044af9e4329478403df Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Mon, 25 Mar 2024 16:55:03 +0100
Subject: [PATCH 3/8] [Clang] Sema and tests
---
.../clang/Basic/DiagnosticSemaKinds.td | 7 ++--
clang/include/clang/Sema/Sema.h | 5 +++
clang/lib/Sema/SemaExpr.cpp | 7 ++--
clang/lib/Sema/SemaExprCXX.cpp | 23 ++++++-------
clang/lib/Sema/SemaOverload.cpp | 32 ++++++++++++-------
.../lib/Sema/SemaTemplateInstantiateDecl.cpp | 11 ++-----
.../SemaCXX/cxx2c-delete-with-message.cpp | 30 +++++++++++++++++
7 files changed, 76 insertions(+), 39 deletions(-)
create mode 100644 clang/test/SemaCXX/cxx2c-delete-with-message.cpp
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index d7ab1635cf12bc..37197b60ddfbb8 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -4661,11 +4661,10 @@ def err_ovl_no_viable_member_function_in_call : Error<
"no matching member function for call to %0">;
def err_ovl_ambiguous_call : Error<
"call to %0 is ambiguous">;
-def err_ovl_deleted_call : Error<"call to deleted function %0">;
+def err_ovl_deleted_call : Error<"call to deleted"
+ "%select{| member}0 function %1%select{|: %3}2">;
def err_ovl_ambiguous_member_call : Error<
"call to member function %0 is ambiguous">;
-def err_ovl_deleted_member_call : Error<
- "call to deleted member function %0">;
def note_ovl_too_many_candidates : Note<
"remaining %0 candidate%s0 omitted; "
"pass -fshow-overloads=all to show them">;
@@ -8857,7 +8856,7 @@ def err_nontemporal_builtin_must_be_pointer_intfltptr_or_vector : Error<
"address argument to nontemporal builtin must be a pointer to integer, float, "
"pointer, or a vector of such types (%0 invalid)">;
-def err_deleted_function_use : Error<"attempt to use a deleted function">;
+def err_deleted_function_use : Error<"attempt to use a deleted function%select{|: %1}0">;
def err_deleted_inherited_ctor_use : Error<
"constructor inherited by %0 from base class %1 is implicitly deleted">;
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 919f8f6b0a35a2..9f6e2639508b2a 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -8264,6 +8264,11 @@ class Sema final {
bool IsFunctionConversion(QualType FromType, QualType ToType,
QualType &ResultTy);
bool DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType);
+ void DiagnoseUseOfDeletedFunction(SourceLocation Loc, SourceRange Range,
+ DeclarationName Name,
+ OverloadCandidateSet &CandidateSet,
+ FunctionDecl *Fn, MultiExprArg Args,
+ bool IsMember = false);
ExprResult InitializeExplicitObjectArgument(Sema &S, Expr *Obj,
FunctionDecl *Fun);
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 8725b09f8546cf..468b5ed1010457 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -271,8 +271,11 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
Diag(Loc, diag::err_deleted_inherited_ctor_use)
<< Ctor->getParent()
<< Ctor->getInheritedConstructor().getConstructor()->getParent();
- else
- Diag(Loc, diag::err_deleted_function_use);
+ else {
+ StringLiteral *Msg = FD->getDeletedMessage();
+ Diag(Loc, diag::err_deleted_function_use)
+ << !!Msg << (Msg ? Msg->getString() : StringRef());
+ }
NoteDeletedFunction(FD);
return true;
}
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index c34a40fa7c81ac..ff1fb146544d40 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -2663,13 +2663,9 @@ static bool resolveAllocationOverload(
return true;
case OR_Deleted: {
- if (Diagnose) {
- Candidates.NoteCandidates(
- PartialDiagnosticAt(R.getNameLoc(),
- S.PDiag(diag::err_ovl_deleted_call)
- << R.getLookupName() << Range),
- S, OCD_AllCandidates, Args);
- }
+ if (Diagnose)
+ S.DiagnoseUseOfDeletedFunction(R.getNameLoc(), Range, R.getLookupName(),
+ Candidates, Best->Function, Args);
return true;
}
}
@@ -3323,7 +3319,9 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD,
// FIXME: DiagnoseUseOfDecl?
if (Operator->isDeleted()) {
if (Diagnose) {
- Diag(StartLoc, diag::err_deleted_function_use);
+ StringLiteral *Msg = Operator->getDeletedMessage();
+ Diag(StartLoc, diag::err_deleted_function_use)
+ << !!Msg << (Msg ? Msg->getString() : StringRef());
NoteDeletedFunction(Operator);
}
return true;
@@ -3927,14 +3925,11 @@ static bool resolveBuiltinNewDeleteOverload(Sema &S, CallExpr *TheCall,
S, OCD_AmbiguousCandidates, Args);
return true;
- case OR_Deleted: {
- Candidates.NoteCandidates(
- PartialDiagnosticAt(R.getNameLoc(), S.PDiag(diag::err_ovl_deleted_call)
- << R.getLookupName() << Range),
- S, OCD_AllCandidates, Args);
+ case OR_Deleted:
+ S.DiagnoseUseOfDeletedFunction(R.getNameLoc(), Range, R.getLookupName(),
+ Candidates, Best->Function, Args);
return true;
}
- }
llvm_unreachable("Unreachable, bad result from BestViableFunction");
}
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 4e03c3124e39ab..e4350df47c3570 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -14138,15 +14138,13 @@ static ExprResult FinishOverloadedCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
break;
case OR_Deleted: {
- CandidateSet->NoteCandidates(
- PartialDiagnosticAt(Fn->getBeginLoc(),
- SemaRef.PDiag(diag::err_ovl_deleted_call)
- << ULE->getName() << Fn->getSourceRange()),
- SemaRef, OCD_AllCandidates, Args);
+ FunctionDecl *FDecl = (*Best)->Function;
+ SemaRef.DiagnoseUseOfDeletedFunction(Fn->getBeginLoc(),
+ Fn->getSourceRange(), ULE->getName(),
+ *CandidateSet, FDecl, Args);
// We emitted an error for the unavailable/deleted function call but keep
// the call in the AST.
- FunctionDecl *FDecl = (*Best)->Function;
ExprResult Res =
SemaRef.FixOverloadedFunctionReference(Fn, (*Best)->FoundDecl, FDecl);
if (Res.isInvalid())
@@ -15588,11 +15586,9 @@ ExprResult Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
*this, OCD_AmbiguousCandidates, Args);
break;
case OR_Deleted:
- CandidateSet.NoteCandidates(
- PartialDiagnosticAt(UnresExpr->getMemberLoc(),
- PDiag(diag::err_ovl_deleted_member_call)
- << DeclName << MemExprE->getSourceRange()),
- *this, OCD_AllCandidates, Args);
+ DiagnoseUseOfDeletedFunction(
+ UnresExpr->getMemberLoc(), MemExprE->getSourceRange(), DeclName,
+ CandidateSet, Best->Function, Args, /*IsMember=*/true);
break;
}
// Overload resolution fails, try to recover.
@@ -16483,3 +16479,17 @@ bool clang::shouldEnforceArgLimit(bool PartialOverloading,
return false;
return true;
}
+
+void Sema::DiagnoseUseOfDeletedFunction(SourceLocation Loc, SourceRange Range,
+ DeclarationName Name,
+ OverloadCandidateSet &CandidateSet,
+ FunctionDecl *Fn, MultiExprArg Args,
+ bool IsMember) {
+ StringLiteral *Msg = Fn->getDeletedMessage();
+ CandidateSet.NoteCandidates(
+ PartialDiagnosticAt(Loc, PDiag(diag::err_ovl_deleted_call)
+ << IsMember << Name << !!Msg
+ << (Msg ? Msg->getString() : StringRef())
+ << Range),
+ *this, OCD_AllCandidates, Args);
+}
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 549ffd4b0b6df5..dfc6edc003e641 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -2202,9 +2202,6 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
if (D->isLocalExternDecl())
Function->setLocalExternDecl();
- if (D->isDeletedAsWritten())
- Function->setDeletedWithMessage(D->getDeletedMessage());
-
DeclContext *LexicalDC = Owner;
if (!isFriend && D->isOutOfLine() && !D->isLocalExternDecl()) {
assert(D->getDeclContext()->isFileContext());
@@ -2432,7 +2429,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
return nullptr;
}
if (D->isDeleted())
- SemaRef.SetDeclDeleted(Function, D->getLocation());
+ SemaRef.SetDeclDeleted(Function, D->getLocation(), D->getDeletedMessage());
NamedDecl *PrincipalDecl =
(TemplateParams ? cast<NamedDecl>(FunctionTemplate) : Function);
@@ -2630,9 +2627,6 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
if (QualifierLoc)
Method->setQualifierInfo(QualifierLoc);
- if (D->isDeletedAsWritten())
- Method->setDeletedWithMessage(D->getDeletedMessage());
-
if (TemplateParams) {
// Our resulting instantiation is actually a function template, since we
// are substituting only the outer template parameters. For example, given
@@ -2811,7 +2805,8 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
return nullptr;
}
if (D->isDeletedAsWritten())
- SemaRef.SetDeclDeleted(Method, Method->getLocation());
+ SemaRef.SetDeclDeleted(Method, Method->getLocation(),
+ D->getDeletedMessage());
// If this is an explicit specialization, mark the implicitly-instantiated
// template specialization as being an explicit specialization too.
diff --git a/clang/test/SemaCXX/cxx2c-delete-with-message.cpp b/clang/test/SemaCXX/cxx2c-delete-with-message.cpp
new file mode 100644
index 00000000000000..d0f62859c547e6
--- /dev/null
+++ b/clang/test/SemaCXX/cxx2c-delete-with-message.cpp
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -std=c++2c -fsyntax-only -verify %s
+
+struct S {
+ void f() = delete("deleted (1)"); // expected-note {{explicitly marked deleted}}
+
+ template <typename T>
+ T g() = delete("deleted (2)"); // expected-note {{explicitly deleted}}
+};
+
+template <typename T>
+struct TS {
+ T f() = delete("deleted (3)"); // expected-note {{explicitly marked deleted}}
+
+ template <typename U>
+ T g(U) = delete("deleted (4)"); // expected-note {{explicitly deleted}}
+};
+
+void f() = delete("deleted (5)"); // expected-note {{explicitly deleted}}
+
+template <typename T>
+T g() = delete("deleted (6)"); // expected-note {{explicitly deleted}}
+
+void h() {
+ S{}.f(); // expected-error {{attempt to use a deleted function: deleted (1)}}
+ S{}.g<int>(); // expected-error {{call to deleted member function 'g': deleted (2)}}
+ TS<int>{}.f(); // expected-error {{attempt to use a deleted function: deleted (3)}}
+ TS<int>{}.g<int>(0); // expected-error {{call to deleted member function 'g': deleted (4)}}
+ f(); // expected-error {{call to deleted function 'f': deleted (5)}}
+ g<int>(); // expected-error {{call to deleted function 'g': deleted (6)}}
+}
>From a018c8814b024ca08f5487be5be9132aa5c99dfe Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Mon, 25 Mar 2024 17:00:14 +0100
Subject: [PATCH 4/8] [Clang] Add ast printer tests
---
.../ast-print-cxx2c-delete-with-message.cpp | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
create mode 100644 clang/test/SemaCXX/ast-print-cxx2c-delete-with-message.cpp
diff --git a/clang/test/SemaCXX/ast-print-cxx2c-delete-with-message.cpp b/clang/test/SemaCXX/ast-print-cxx2c-delete-with-message.cpp
new file mode 100644
index 00000000000000..edc9544d718d19
--- /dev/null
+++ b/clang/test/SemaCXX/ast-print-cxx2c-delete-with-message.cpp
@@ -0,0 +1,18 @@
+// Without serialization:
+// RUN: %clang_cc1 -ast-print %s | FileCheck %s
+//
+// With serialization:
+// RUN: %clang_cc1 -emit-pch -o %t %s
+// RUN: %clang_cc1 -x c++ -include-pch %t -ast-print-all /dev/null | FileCheck %s
+
+// CHECK: struct S {
+struct S {
+ // CHECK-NEXT: void a() = delete("foo");
+ void a() = delete("foo");
+
+ // CHECK-NEXT: template <typename T> T b() = delete("bar");
+ template <typename T> T b() = delete("bar");
+};
+
+// CHECK: void c() = delete("baz");
+void c() = delete("baz");
>From b5a50beebc1f54fd106ebeda086b73c6875591a5 Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Mon, 25 Mar 2024 17:08:04 +0100
Subject: [PATCH 5/8] [NFC] clang-format
---
clang/include/clang/AST/Decl.h | 2 +-
clang/lib/Parse/ParseCXXInlineMethods.cpp | 7 ++++---
clang/lib/Sema/SemaDeclCXX.cpp | 3 ++-
clang/lib/Sema/SemaExpr.cpp | 2 +-
clang/lib/Sema/SemaExprCXX.cpp | 2 +-
5 files changed, 9 insertions(+), 7 deletions(-)
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 24f0394577e228..9c445eccdf8992 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -2489,7 +2489,7 @@ class FunctionDecl : public DeclaratorDecl,
}
void setDeletedAsWritten(bool D = true) { FunctionDeclBits.IsDeleted = D; }
- void setDeletedWithMessage(StringLiteral* Message) {
+ void setDeletedWithMessage(StringLiteral *Message) {
FunctionDeclBits.IsDeleted = true;
DeletedMessage = Message;
}
diff --git a/clang/lib/Parse/ParseCXXInlineMethods.cpp b/clang/lib/Parse/ParseCXXInlineMethods.cpp
index c551023a1e9dbc..9e2f4ce562a4ea 100644
--- a/clang/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/clang/lib/Parse/ParseCXXInlineMethods.cpp
@@ -22,7 +22,8 @@ using namespace clang;
/// Parse the optional ("message") part of a deleted-function-body.
StringLiteral *Parser::ParseCXXDeletedFunctionMessage() {
- if (!Tok.is(tok::l_paren)) return nullptr;
+ if (!Tok.is(tok::l_paren))
+ return nullptr;
StringLiteral *Message = nullptr;
BalancedDelimiterTracker BT{*this, tok::l_paren};
BT.consumeOpen();
@@ -33,7 +34,7 @@ StringLiteral *Parser::ParseCXXDeletedFunctionMessage() {
Message = Res.getAs<StringLiteral>();
} else {
Diag(Tok.getLocation(), diag::err_expected_string_literal)
- << /*Source='in'*/ 0 << "'delete'";
+ << /*Source='in'*/ 0 << "'delete'";
SkipUntil(tok::r_paren, StopAtSemi | StopBeforeMatch);
}
@@ -91,7 +92,7 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(
? diag::warn_cxx98_compat_defaulted_deleted_function
: diag::ext_defaulted_deleted_function)
<< 1 /* deleted */;
- StringLiteral* Message = ParseCXXDeletedFunctionMessage();
+ StringLiteral *Message = ParseCXXDeletedFunctionMessage();
Actions.SetDeclDeleted(FnD, KWLoc, Message);
Delete = true;
if (auto *DeclAsFunction = dyn_cast<FunctionDecl>(FnD)) {
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index e6d653aedd061c..50eff9b02cbef8 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -18108,7 +18108,8 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
return ND;
}
-void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc, StringLiteral *Message) {
+void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc,
+ StringLiteral *Message) {
AdjustDeclIfTemplate(Dcl);
FunctionDecl *Fn = dyn_cast_or_null<FunctionDecl>(Dcl);
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 468b5ed1010457..76fbce8a95da85 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -274,7 +274,7 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
else {
StringLiteral *Msg = FD->getDeletedMessage();
Diag(Loc, diag::err_deleted_function_use)
- << !!Msg << (Msg ? Msg->getString() : StringRef());
+ << !!Msg << (Msg ? Msg->getString() : StringRef());
}
NoteDeletedFunction(FD);
return true;
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index ff1fb146544d40..e5b8d1fbb81554 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -3321,7 +3321,7 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD,
if (Diagnose) {
StringLiteral *Msg = Operator->getDeletedMessage();
Diag(StartLoc, diag::err_deleted_function_use)
- << !!Msg << (Msg ? Msg->getString() : StringRef());
+ << !!Msg << (Msg ? Msg->getString() : StringRef());
NoteDeletedFunction(Operator);
}
return true;
>From e48b80d477e10d4cf3b267a968eaa3cdfaf8c8d3 Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Mon, 25 Mar 2024 17:28:26 +0100
Subject: [PATCH 6/8] [Clang] Add release note
---
clang/docs/ReleaseNotes.rst | 2 ++
1 file changed, 2 insertions(+)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 459f6a25aeef7b..d838e9b5f287f6 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -109,6 +109,8 @@ C++2c Feature Support
- Implemented `P2662R3 Pack Indexing <https://wg21.link/P2662R3>`_.
+- Implemented `P2573R2: = delete("should have a reason"); <https://wg21.link/P2573R2>`_
+
Resolutions to C++ Defect Reports
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>From 9e45341bf798fc54c0d95bdd7ac585e11e2d11b1 Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Mon, 25 Mar 2024 18:34:17 +0100
Subject: [PATCH 7/8] [Clang] Move test to the right directory and fix typo
---
.../{SemaCXX => AST}/ast-print-cxx2c-delete-with-message.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
rename clang/test/{SemaCXX => AST}/ast-print-cxx2c-delete-with-message.cpp (83%)
diff --git a/clang/test/SemaCXX/ast-print-cxx2c-delete-with-message.cpp b/clang/test/AST/ast-print-cxx2c-delete-with-message.cpp
similarity index 83%
rename from clang/test/SemaCXX/ast-print-cxx2c-delete-with-message.cpp
rename to clang/test/AST/ast-print-cxx2c-delete-with-message.cpp
index edc9544d718d19..11e037e4d7443e 100644
--- a/clang/test/SemaCXX/ast-print-cxx2c-delete-with-message.cpp
+++ b/clang/test/AST/ast-print-cxx2c-delete-with-message.cpp
@@ -3,7 +3,7 @@
//
// With serialization:
// RUN: %clang_cc1 -emit-pch -o %t %s
-// RUN: %clang_cc1 -x c++ -include-pch %t -ast-print-all /dev/null | FileCheck %s
+// RUN: %clang_cc1 -x c++ -include-pch %t -ast-print /dev/null | FileCheck %s
// CHECK: struct S {
struct S {
>From 9fc02a5e6dde90375b8355e28856ee598b3ca1fe Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Tue, 26 Mar 2024 14:31:59 +0100
Subject: [PATCH 8/8] [NFC] Spell out type
Co-authored-by: Mariya Podchishchaeva <mariya.podchishchaeva at intel.com>
---
clang/lib/AST/DeclPrinter.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp
index d04cdd5a10e033..ae79398029b3c6 100644
--- a/clang/lib/AST/DeclPrinter.cpp
+++ b/clang/lib/AST/DeclPrinter.cpp
@@ -875,7 +875,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
Out << " = 0";
else if (D->isDeletedAsWritten()) {
Out << " = delete";
- if (const auto *M = D->getDeletedMessage()) {
+ if (const StringLiteral *M = D->getDeletedMessage()) {
Out << "(";
M->outputString(Out);
Out << ")";
More information about the cfe-commits
mailing list