forked from OSchip/llvm-project
Parse deleted function definitions and hook them up to Doug's machinery.
llvm-svn: 67653
This commit is contained in:
parent
d1d2c50ea7
commit
f769df5ef9
|
@ -618,6 +618,8 @@ public:
|
||||||
/// declaration of the function is also a definition. This does not
|
/// declaration of the function is also a definition. This does not
|
||||||
/// determine whether the function has been defined (e.g., in a
|
/// determine whether the function has been defined (e.g., in a
|
||||||
/// previous definition); for that information, use getBody.
|
/// 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; }
|
bool isThisDeclarationADefinition() const { return Body != 0; }
|
||||||
|
|
||||||
void setBody(CompoundStmt *B) { Body = (Stmt*) B; }
|
void setBody(CompoundStmt *B) { Body = (Stmt*) B; }
|
||||||
|
|
|
@ -228,7 +228,12 @@ def err_allocation_of_abstract_type : Error<
|
||||||
|
|
||||||
def note_pure_virtual_function : Note<
|
def note_pure_virtual_function : Note<
|
||||||
"pure virtual function %0">;
|
"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
|
// C++ name lookup
|
||||||
def err_incomplete_nested_name_spec : Error<
|
def err_incomplete_nested_name_spec : Error<
|
||||||
"incomplete type %0 named in nested name specifier">;
|
"incomplete type %0 named in nested name specifier">;
|
||||||
|
|
|
@ -234,6 +234,14 @@ public:
|
||||||
return;
|
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
|
/// ActOnUninitializedDecl - This action is called immediately after
|
||||||
/// ActOnDeclarator (when an initializer is *not* present).
|
/// ActOnDeclarator (when an initializer is *not* present).
|
||||||
virtual void ActOnUninitializedDecl(DeclTy *Dcl) {
|
virtual void ActOnUninitializedDecl(DeclTy *Dcl) {
|
||||||
|
|
|
@ -225,7 +225,7 @@ void Parser::FuzzyParseMicrosoftDeclSpec() {
|
||||||
/// [C++] namespace-definition
|
/// [C++] namespace-definition
|
||||||
/// [C++] using-directive
|
/// [C++] using-directive
|
||||||
/// [C++] using-declaration [TODO]
|
/// [C++] using-declaration [TODO]
|
||||||
// [C++0x] static_assert-declaration
|
/// [C++0x] static_assert-declaration
|
||||||
/// others... [FIXME]
|
/// others... [FIXME]
|
||||||
///
|
///
|
||||||
Parser::DeclTy *Parser::ParseDeclaration(unsigned Context) {
|
Parser::DeclTy *Parser::ParseDeclaration(unsigned Context) {
|
||||||
|
@ -285,6 +285,11 @@ Parser::DeclTy *Parser::ParseSimpleDeclaration(unsigned Context) {
|
||||||
/// [C++] initializer:
|
/// [C++] initializer:
|
||||||
/// [C++] '=' initializer-clause
|
/// [C++] '=' initializer-clause
|
||||||
/// [C++] '(' expression-list ')'
|
/// [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::
|
Parser::DeclTy *Parser::
|
||||||
ParseInitDeclaratorListAfterFirstDeclarator(Declarator &D) {
|
ParseInitDeclaratorListAfterFirstDeclarator(Declarator &D) {
|
||||||
|
@ -322,12 +327,17 @@ ParseInitDeclaratorListAfterFirstDeclarator(Declarator &D) {
|
||||||
// Parse declarator '=' initializer.
|
// Parse declarator '=' initializer.
|
||||||
if (Tok.is(tok::equal)) {
|
if (Tok.is(tok::equal)) {
|
||||||
ConsumeToken();
|
ConsumeToken();
|
||||||
OwningExprResult Init(ParseInitializer());
|
if (getLang().CPlusPlus0x && Tok.is(tok::kw_delete)) {
|
||||||
if (Init.isInvalid()) {
|
SourceLocation DelLoc = ConsumeToken();
|
||||||
SkipUntil(tok::semi);
|
Actions.SetDeclDeleted(LastDeclInGroup, DelLoc);
|
||||||
return 0;
|
} 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)) {
|
} else if (Tok.is(tok::l_paren)) {
|
||||||
// Parse C++ direct initializer: '(' expression-list ')'
|
// Parse C++ direct initializer: '(' expression-list ')'
|
||||||
SourceLocation LParenLoc = ConsumeParen();
|
SourceLocation LParenLoc = ConsumeParen();
|
||||||
|
@ -2037,13 +2047,13 @@ void Parser::ParseParenDeclarator(Declarator &D) {
|
||||||
/// declaration-specifiers declarator
|
/// declaration-specifiers declarator
|
||||||
/// [C++] declaration-specifiers declarator '=' assignment-expression
|
/// [C++] declaration-specifiers declarator '=' assignment-expression
|
||||||
/// [GNU] declaration-specifiers declarator attributes
|
/// [GNU] declaration-specifiers declarator attributes
|
||||||
/// declaration-specifiers abstract-declarator[opt]
|
/// declaration-specifiers abstract-declarator[opt]
|
||||||
/// [C++] declaration-specifiers abstract-declarator[opt]
|
/// [C++] declaration-specifiers abstract-declarator[opt]
|
||||||
/// '=' assignment-expression
|
/// '=' assignment-expression
|
||||||
/// [GNU] declaration-specifiers abstract-declarator[opt] attributes
|
/// [GNU] declaration-specifiers abstract-declarator[opt] attributes
|
||||||
///
|
///
|
||||||
/// For C++, after the parameter-list, it also parses "cv-qualifier-seq[opt]"
|
/// 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,
|
void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
|
||||||
AttributeList *AttrList,
|
AttributeList *AttrList,
|
||||||
|
|
|
@ -363,6 +363,7 @@ public:
|
||||||
virtual void AddInitializerToDecl(DeclTy *dcl, ExprArg init);
|
virtual void AddInitializerToDecl(DeclTy *dcl, ExprArg init);
|
||||||
void AddInitializerToDecl(DeclTy *dcl, ExprArg init, bool DirectInit);
|
void AddInitializerToDecl(DeclTy *dcl, ExprArg init, bool DirectInit);
|
||||||
void ActOnUninitializedDecl(DeclTy *dcl);
|
void ActOnUninitializedDecl(DeclTy *dcl);
|
||||||
|
virtual void SetDeclDeleted(DeclTy *dcl, SourceLocation DelLoc);
|
||||||
virtual DeclTy *FinalizeDeclaratorGroup(Scope *S, DeclTy *Group);
|
virtual DeclTy *FinalizeDeclaratorGroup(Scope *S, DeclTy *Group);
|
||||||
|
|
||||||
virtual void ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D);
|
virtual void ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D);
|
||||||
|
|
|
@ -2501,3 +2501,19 @@ Sema::DeclTy *Sema::ActOnStaticAssertDeclaration(SourceLocation AssertLoc,
|
||||||
CurContext->addDecl(Decl);
|
CurContext->addDecl(Decl);
|
||||||
return 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();
|
||||||
|
}
|
||||||
|
|
|
@ -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'}}
|
||||||
|
}
|
Loading…
Reference in New Issue