diff options
author | Sebastian Redl <sebastian.redl@getdesigned.at> | 2009-03-24 22:27:57 +0000 |
---|---|---|
committer | Sebastian Redl <sebastian.redl@getdesigned.at> | 2009-03-24 22:27:57 +0000 |
commit | 50de12f5783b57c74fd30ebfa3945181313625ff (patch) | |
tree | cfa3b0dd1ca4ab29aebd1b216fd0ebba653aa063 | |
parent | 8d9aefcb479cf2d1a5e397114ed3e22429ab9ac0 (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.h | 2 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 7 | ||||
-rw-r--r-- | include/clang/Parse/Action.h | 8 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 28 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 1 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 16 | ||||
-rw-r--r-- | test/SemaCXX/deleted-function.cpp | 22 |
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'}} +} |