aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Redl <sebastian.redl@getdesigned.at>2009-03-24 22:27:57 +0000
committerSebastian Redl <sebastian.redl@getdesigned.at>2009-03-24 22:27:57 +0000
commit50de12f5783b57c74fd30ebfa3945181313625ff (patch)
treecfa3b0dd1ca4ab29aebd1b216fd0ebba653aa063
parent8d9aefcb479cf2d1a5e397114ed3e22429ab9ac0 (diff)
Parse deleted function definitions and hook them up to Doug's machinery.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@67653 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/AST/Decl.h2
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td7
-rw-r--r--include/clang/Parse/Action.h8
-rw-r--r--lib/Parse/ParseDecl.cpp28
-rw-r--r--lib/Sema/Sema.h1
-rw-r--r--lib/Sema/SemaDeclCXX.cpp16
-rw-r--r--test/SemaCXX/deleted-function.cpp22
7 files changed, 74 insertions, 10 deletions
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index b1c4feedcb..34b863512b 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -618,6 +618,8 @@ public:
/// declaration of the function is also a definition. This does not
/// determine whether the function has been defined (e.g., in a
/// previous definition); for that information, use getBody.
+ /// FIXME: Should return true if function is deleted or defaulted. However,
+ /// CodeGenModule.cpp uses it, and I don't know if this would break it.
bool isThisDeclarationADefinition() const { return Body != 0; }
void setBody(CompoundStmt *B) { Body = (Stmt*) B; }
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index daf1d9cdb3..82f2001ede 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -228,7 +228,12 @@ def err_allocation_of_abstract_type : Error<
def note_pure_virtual_function : Note<
"pure virtual function %0">;
-
+
+def err_deleted_non_function : Error<
+ "only functions can have deleted definitions">;
+def err_deleted_decl_not_first : Error<
+ "deleted definition must be first declaration">;
+
// C++ name lookup
def err_incomplete_nested_name_spec : Error<
"incomplete type %0 named in nested name specifier">;
diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h
index 844b99a6b1..4ff1ac175d 100644
--- a/include/clang/Parse/Action.h
+++ b/include/clang/Parse/Action.h
@@ -234,6 +234,14 @@ public:
return;
}
+ /// SetDeclDeleted - This action is called immediately after ActOnDeclarator
+ /// if =delete is parsed. C++0x [dcl.fct.def]p10
+ /// Note that this can be called even for variable declarations. It's the
+ /// action's job to reject it.
+ virtual void SetDeclDeleted(DeclTy *Dcl, SourceLocation DelLoc) {
+ return;
+ }
+
/// ActOnUninitializedDecl - This action is called immediately after
/// ActOnDeclarator (when an initializer is *not* present).
virtual void ActOnUninitializedDecl(DeclTy *Dcl) {
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 4649abad46..81685eb8ca 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -225,7 +225,7 @@ void Parser::FuzzyParseMicrosoftDeclSpec() {
/// [C++] namespace-definition
/// [C++] using-directive
/// [C++] using-declaration [TODO]
-// [C++0x] static_assert-declaration
+/// [C++0x] static_assert-declaration
/// others... [FIXME]
///
Parser::DeclTy *Parser::ParseDeclaration(unsigned Context) {
@@ -285,6 +285,11 @@ Parser::DeclTy *Parser::ParseSimpleDeclaration(unsigned Context) {
/// [C++] initializer:
/// [C++] '=' initializer-clause
/// [C++] '(' expression-list ')'
+/// [C++0x] '=' 'default' [TODO]
+/// [C++0x] '=' 'delete'
+///
+/// According to the standard grammar, =default and =delete are function
+/// definitions, but that definitely doesn't fit with the parser here.
///
Parser::DeclTy *Parser::
ParseInitDeclaratorListAfterFirstDeclarator(Declarator &D) {
@@ -322,12 +327,17 @@ ParseInitDeclaratorListAfterFirstDeclarator(Declarator &D) {
// Parse declarator '=' initializer.
if (Tok.is(tok::equal)) {
ConsumeToken();
- OwningExprResult Init(ParseInitializer());
- if (Init.isInvalid()) {
- SkipUntil(tok::semi);
- return 0;
+ if (getLang().CPlusPlus0x && Tok.is(tok::kw_delete)) {
+ SourceLocation DelLoc = ConsumeToken();
+ Actions.SetDeclDeleted(LastDeclInGroup, DelLoc);
+ } else {
+ OwningExprResult Init(ParseInitializer());
+ if (Init.isInvalid()) {
+ SkipUntil(tok::semi);
+ return 0;
+ }
+ Actions.AddInitializerToDecl(LastDeclInGroup, move(Init));
}
- Actions.AddInitializerToDecl(LastDeclInGroup, move(Init));
} else if (Tok.is(tok::l_paren)) {
// Parse C++ direct initializer: '(' expression-list ')'
SourceLocation LParenLoc = ConsumeParen();
@@ -2037,13 +2047,13 @@ void Parser::ParseParenDeclarator(Declarator &D) {
/// declaration-specifiers declarator
/// [C++] declaration-specifiers declarator '=' assignment-expression
/// [GNU] declaration-specifiers declarator attributes
-/// declaration-specifiers abstract-declarator[opt]
-/// [C++] declaration-specifiers abstract-declarator[opt]
+/// declaration-specifiers abstract-declarator[opt]
+/// [C++] declaration-specifiers abstract-declarator[opt]
/// '=' assignment-expression
/// [GNU] declaration-specifiers abstract-declarator[opt] attributes
///
/// For C++, after the parameter-list, it also parses "cv-qualifier-seq[opt]"
-/// and "exception-specification[opt]"(TODO).
+/// and "exception-specification[opt]".
///
void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
AttributeList *AttrList,
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 90ef136785..46df1c7674 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -363,6 +363,7 @@ public:
virtual void AddInitializerToDecl(DeclTy *dcl, ExprArg init);
void AddInitializerToDecl(DeclTy *dcl, ExprArg init, bool DirectInit);
void ActOnUninitializedDecl(DeclTy *dcl);
+ virtual void SetDeclDeleted(DeclTy *dcl, SourceLocation DelLoc);
virtual DeclTy *FinalizeDeclaratorGroup(Scope *S, DeclTy *Group);
virtual void ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D);
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index af71e71ec8..a85d62bc41 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -2501,3 +2501,19 @@ Sema::DeclTy *Sema::ActOnStaticAssertDeclaration(SourceLocation AssertLoc,
CurContext->addDecl(Decl);
return Decl;
}
+
+void Sema::SetDeclDeleted(DeclTy *dcl, SourceLocation DelLoc) {
+ Decl *Dcl = static_cast<Decl*>(dcl);
+ FunctionDecl *Fn = dyn_cast<FunctionDecl>(Dcl);
+ if (!Fn) {
+ Diag(DelLoc, diag::err_deleted_non_function);
+ return;
+ }
+ if (const FunctionDecl *Prev = Fn->getPreviousDeclaration()) {
+ Diag(DelLoc, diag::err_deleted_decl_not_first);
+ Diag(Prev->getLocation(), diag::note_previous_declaration);
+ // If the declaration wasn't the first, we delete the function anyway for
+ // recovery.
+ }
+ Fn->setDeleted();
+}
diff --git a/test/SemaCXX/deleted-function.cpp b/test/SemaCXX/deleted-function.cpp
new file mode 100644
index 0000000000..59a8260334
--- /dev/null
+++ b/test/SemaCXX/deleted-function.cpp
@@ -0,0 +1,22 @@
+// RUN: clang-cc -fsyntax-only -verify -std=c++0x %s
+
+int i = delete; // expected-error {{only functions can have deleted definitions}}
+
+void fn() = delete; // expected-note {{candidate function has been explicitly deleted}}
+
+void fn2(); // expected-note {{previous declaration is here}}
+void fn2() = delete; // expected-error {{deleted definition must be first declaration}}
+
+void fn3() = delete;
+void fn3() {
+ // FIXME: This definition should be invalid.
+}
+
+void ov(int) {} // expected-note {{candidate function}}
+void ov(double) = delete; // expected-note {{candidate function has been explicitly deleted}}
+
+void test() {
+ fn(); // expected-error {{call to deleted function 'fn'}}
+ ov(1);
+ ov(1.0); // expected-error {{call to deleted function 'ov'}}
+}