Properly parse the 'default' and 'delete' keywords.

They are actually grammatically considered definitions and parsed
accordingly.

This fixes the outstanding bugs regarding defaulting functions after
their declarations.

We now really nicely diagnose the following construct (try it!)

int foo() = delete, bar;

Still todo: Defaulted functions other than default constructors
            Test cases (including for the above construct)

llvm-svn: 131228
This commit is contained in:
Alexis Hunt 2011-05-12 06:15:49 +00:00
parent f92197cf96
commit 5a7fa250ab
11 changed files with 213 additions and 79 deletions

View File

@ -56,6 +56,8 @@ def err_default_special_members : Error<
"only special member functions may be defaulted">; "only special member functions may be defaulted">;
def err_friends_define_only_namespace_scope : Error< def err_friends_define_only_namespace_scope : Error<
"cannot define a function with non-namespace scope in a friend declaration">; "cannot define a function with non-namespace scope in a friend declaration">;
def err_deleted_non_function : Error<
"only functions can have deleted definitions">;
// Sema && Lex // Sema && Lex
def ext_longlong : Extension< def ext_longlong : Extension<

View File

@ -343,6 +343,9 @@ def err_operator_string_not_empty : Error<
// Classes. // Classes.
def err_anon_type_definition : Error< def err_anon_type_definition : Error<
"declaration of anonymous %0 must be a definition">; "declaration of anonymous %0 must be a definition">;
def err_default_delete_in_multiple_declaration : Error<
"'= %select{default|delete}0' is a function definition and must occur in a "
"standalone declaration">;
def err_cxx0x_attribute_forbids_arguments : Error< def err_cxx0x_attribute_forbids_arguments : Error<
"C++0x attribute '%0' cannot have an argument list">; "C++0x attribute '%0' cannot have an argument list">;

View File

@ -553,8 +553,6 @@ def err_type_defined_in_alias_template : Error<
def note_pure_virtual_function : Note< def note_pure_virtual_function : Note<
"unimplemented pure virtual method %0 in %1">; "unimplemented pure virtual method %0 in %1">;
def err_deleted_non_function : Error<
"only functions can have deleted definitions">;
def err_deleted_decl_not_first : Error< def err_deleted_decl_not_first : Error<
"deleted definition must be first declaration">; "deleted definition must be first declaration">;

View File

@ -1000,7 +1000,7 @@ private:
DeclGroupPtrTy ParseExternalDeclaration(ParsedAttributesWithRange &attrs, DeclGroupPtrTy ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
ParsingDeclSpec *DS = 0); ParsingDeclSpec *DS = 0);
bool isDeclarationAfterDeclarator() const; bool isDeclarationAfterDeclarator();
bool isStartOfFunctionDefinition(const ParsingDeclarator &Declarator); bool isStartOfFunctionDefinition(const ParsingDeclarator &Declarator);
DeclGroupPtrTy ParseDeclarationOrFunctionDefinition(ParsedAttributes &attrs, DeclGroupPtrTy ParseDeclarationOrFunctionDefinition(ParsedAttributes &attrs,
AccessSpecifier AS = AS_none); AccessSpecifier AS = AS_none);

View File

@ -931,12 +931,12 @@ public:
SourceLocation NameLoc, SourceLocation NameLoc,
const Token &NextToken); const Token &NextToken);
Decl *ActOnDeclarator(Scope *S, Declarator &D); Decl *ActOnDeclarator(Scope *S, Declarator &D,
bool IsFunctionDefintion = false);
Decl *HandleDeclarator(Scope *S, Declarator &D, Decl *HandleDeclarator(Scope *S, Declarator &D,
MultiTemplateParamsArg TemplateParameterLists, MultiTemplateParamsArg TemplateParameterLists,
bool IsFunctionDefinition, bool IsFunctionDefinition);
SourceLocation DefaultLoc = SourceLocation());
void RegisterLocallyScopedExternCDecl(NamedDecl *ND, void RegisterLocallyScopedExternCDecl(NamedDecl *ND,
const LookupResult &Previous, const LookupResult &Previous,
Scope *S); Scope *S);
@ -964,8 +964,7 @@ public:
LookupResult &Previous, LookupResult &Previous,
MultiTemplateParamsArg TemplateParamLists, MultiTemplateParamsArg TemplateParamLists,
bool IsFunctionDefinition, bool IsFunctionDefinition,
bool &Redeclaration, bool &Redeclaration);
SourceLocation DefaultLoc = SourceLocation());
bool AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD); bool AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD);
void DiagnoseHiddenVirtualMethods(CXXRecordDecl *DC, CXXMethodDecl *MD); void DiagnoseHiddenVirtualMethods(CXXRecordDecl *DC, CXXMethodDecl *MD);
void CheckFunctionDeclaration(Scope *S, void CheckFunctionDeclaration(Scope *S,
@ -997,6 +996,7 @@ public:
void ActOnInitializerError(Decl *Dcl); void ActOnInitializerError(Decl *Dcl);
void ActOnCXXForRangeDecl(Decl *D); void ActOnCXXForRangeDecl(Decl *D);
void SetDeclDeleted(Decl *dcl, SourceLocation DelLoc); void SetDeclDeleted(Decl *dcl, SourceLocation DelLoc);
void SetDeclDefaulted(Decl *dcl, SourceLocation DefaultLoc);
void FinalizeDeclaration(Decl *D); void FinalizeDeclaration(Decl *D);
DeclGroupPtrTy FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS, DeclGroupPtrTy FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
Decl **Group, Decl **Group,
@ -3126,9 +3126,7 @@ public:
Declarator &D, Declarator &D,
MultiTemplateParamsArg TemplateParameterLists, MultiTemplateParamsArg TemplateParameterLists,
Expr *BitfieldWidth, const VirtSpecifiers &VS, Expr *BitfieldWidth, const VirtSpecifiers &VS,
Expr *Init, bool IsDefinition, Expr *Init, bool IsDefinition);
bool Deleted = false,
SourceLocation DefaultLoc = SourceLocation());
MemInitResult ActOnMemInitializer(Decl *ConstructorD, MemInitResult ActOnMemInitializer(Decl *ConstructorD,
Scope *S, Scope *S,

View File

@ -25,8 +25,9 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, ParsingDeclarator &D,
const ParsedTemplateInfo &TemplateInfo, const ParsedTemplateInfo &TemplateInfo,
const VirtSpecifiers& VS, ExprResult& Init) { const VirtSpecifiers& VS, ExprResult& Init) {
assert(D.isFunctionDeclarator() && "This isn't a function declarator!"); assert(D.isFunctionDeclarator() && "This isn't a function declarator!");
assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try)) && assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try) ||
"Current token not a '{', ':' or 'try'!"); Tok.is(tok::equal)) &&
"Current token not a '{', ':', '=', or 'try'!");
MultiTemplateParamsArg TemplateParams(Actions, MultiTemplateParamsArg TemplateParams(Actions,
TemplateInfo.TemplateParams ? TemplateInfo.TemplateParams->data() : 0, TemplateInfo.TemplateParams ? TemplateInfo.TemplateParams->data() : 0,
@ -48,6 +49,40 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, ParsingDeclarator &D,
D.complete(FnD); D.complete(FnD);
if (Tok.is(tok::equal)) {
ConsumeToken();
bool Delete = false;
SourceLocation KWLoc;
if (Tok.is(tok::kw_delete)) {
if (!getLang().CPlusPlus0x)
Diag(Tok, diag::warn_deleted_function_accepted_as_extension);
KWLoc = ConsumeToken();
Actions.SetDeclDeleted(FnD, KWLoc);
Delete = true;
} else if (Tok.is(tok::kw_default)) {
if (!getLang().CPlusPlus0x)
Diag(Tok, diag::warn_defaulted_function_accepted_as_extension);
KWLoc = ConsumeToken();
Actions.SetDeclDefaulted(FnD, KWLoc);
} else {
llvm_unreachable("function definition after = not 'delete' or 'default'");
}
if (Tok.is(tok::comma)) {
Diag(KWLoc, diag::err_default_delete_in_multiple_declaration)
<< Delete;
SkipUntil(tok::semi);
} else {
ExpectAndConsume(tok::semi, diag::err_expected_semi_after,
Delete ? "delete" : "default", tok::semi);
}
return FnD;
}
// In delayed template parsing mode, if we are within a class template // In delayed template parsing mode, if we are within a class template
// or if we are about to parse function member template then consume // or if we are about to parse function member template then consume
// the tokens and store them for parsing at the end of the translation unit. // the tokens and store them for parsing at the end of the translation unit.

View File

@ -968,13 +968,16 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
diag::err_invalid_equalequal_after_declarator)) { diag::err_invalid_equalequal_after_declarator)) {
ConsumeToken(); ConsumeToken();
if (Tok.is(tok::kw_delete)) { if (Tok.is(tok::kw_delete)) {
SourceLocation DelLoc = ConsumeToken(); if (D.isFunctionDeclarator())
Diag(ConsumeToken(), diag::err_default_delete_in_multiple_declaration)
if (!getLang().CPlusPlus0x) << 1 /* delete */;
Diag(DelLoc, diag::warn_deleted_function_accepted_as_extension); else
Diag(ConsumeToken(), diag::err_deleted_non_function);
Actions.SetDeclDeleted(ThisDecl, DelLoc);
} else if (Tok.is(tok::kw_default)) { } else if (Tok.is(tok::kw_default)) {
if (D.isFunctionDeclarator())
Diag(Tok, diag::err_default_delete_in_multiple_declaration)
<< 1 /* delete */;
else
Diag(ConsumeToken(), diag::err_default_special_members); Diag(ConsumeToken(), diag::err_default_special_members);
} else { } else {
if (getLang().CPlusPlus && D.getCXXScopeSpec().isSet()) { if (getLang().CPlusPlus && D.getCXXScopeSpec().isSet()) {

View File

@ -1614,10 +1614,21 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
SkipUntil(tok::comma, true, true); SkipUntil(tok::comma, true, true);
} }
bool IsDefinition = false;
// function-definition: // function-definition:
if (Tok.is(tok::l_brace) if (Tok.is(tok::l_brace)) {
|| (DeclaratorInfo.isFunctionDeclarator() && IsDefinition = true;
(Tok.is(tok::colon) || Tok.is(tok::kw_try)))) { } else if (DeclaratorInfo.isFunctionDeclarator()) {
if (Tok.is(tok::colon) || Tok.is(tok::kw_try)) {
IsDefinition = true;
} else if (Tok.is(tok::equal)) {
const Token &KW = NextToken();
if (KW.is(tok::kw_default) || KW.is(tok::kw_delete))
IsDefinition = true;
}
}
if (IsDefinition) {
if (!DeclaratorInfo.isFunctionDeclarator()) { if (!DeclaratorInfo.isFunctionDeclarator()) {
Diag(Tok, diag::err_func_def_no_params); Diag(Tok, diag::err_func_def_no_params);
ConsumeBrace(); ConsumeBrace();
@ -1644,9 +1655,11 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
} }
ParseCXXInlineMethodDef(AS, DeclaratorInfo, TemplateInfo, VS, Init); ParseCXXInlineMethodDef(AS, DeclaratorInfo, TemplateInfo, VS, Init);
// Consume the optional ';'
if (Tok.is(tok::semi)) // Consume the ';' - it's optional unless we have a delete or default
if (Tok.is(tok::semi)) {
ConsumeToken(); ConsumeToken();
}
return; return;
} }
@ -1658,8 +1671,6 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
llvm::SmallVector<Decl *, 8> DeclsInGroup; llvm::SmallVector<Decl *, 8> DeclsInGroup;
ExprResult BitfieldSize; ExprResult BitfieldSize;
bool Deleted = false;
SourceLocation DefaultLoc;
while (1) { while (1) {
// member-declarator: // member-declarator:
@ -1687,14 +1698,17 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
if (Tok.is(tok::equal)) { if (Tok.is(tok::equal)) {
ConsumeToken(); ConsumeToken();
if (Tok.is(tok::kw_delete)) { if (Tok.is(tok::kw_delete)) {
if (!getLang().CPlusPlus0x) if (DeclaratorInfo.isFunctionDeclarator())
Diag(Tok, diag::warn_deleted_function_accepted_as_extension); Diag(ConsumeToken(), diag::err_default_delete_in_multiple_declaration)
ConsumeToken(); << 1 /* delete */;
Deleted = true; else
Diag(ConsumeToken(), diag::err_deleted_non_function);
} else if (Tok.is(tok::kw_default)) { } else if (Tok.is(tok::kw_default)) {
if (!getLang().CPlusPlus0x) if (DeclaratorInfo.isFunctionDeclarator())
Diag(Tok, diag::warn_defaulted_function_accepted_as_extension); Diag(Tok, diag::err_default_delete_in_multiple_declaration)
DefaultLoc = ConsumeToken(); << 1 /* delete */;
else
Diag(ConsumeToken(), diag::err_default_special_members);
} else { } else {
Init = ParseInitializer(); Init = ParseInitializer();
if (Init.isInvalid()) if (Init.isInvalid())
@ -1722,9 +1736,6 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
Decl *ThisDecl = 0; Decl *ThisDecl = 0;
if (DS.isFriendSpecified()) { if (DS.isFriendSpecified()) {
if (DefaultLoc.isValid())
Diag(DefaultLoc, diag::err_default_special_members);
// TODO: handle initializers, bitfields, 'delete' // TODO: handle initializers, bitfields, 'delete'
ThisDecl = Actions.ActOnFriendFunctionDecl(getCurScope(), DeclaratorInfo, ThisDecl = Actions.ActOnFriendFunctionDecl(getCurScope(), DeclaratorInfo,
/*IsDefinition*/ false, /*IsDefinition*/ false,
@ -1734,9 +1745,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
DeclaratorInfo, DeclaratorInfo,
move(TemplateParams), move(TemplateParams),
BitfieldSize.release(), BitfieldSize.release(),
VS, Init.release(), VS, Init.release(), false);
/*IsDefinition*/Deleted,
Deleted, DefaultLoc);
} }
if (ThisDecl) if (ThisDecl)
DeclsInGroup.push_back(ThisDecl); DeclsInGroup.push_back(ThisDecl);
@ -1762,8 +1771,6 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
VS.clear(); VS.clear();
BitfieldSize = 0; BitfieldSize = 0;
Init = 0; Init = 0;
Deleted = false;
DefaultLoc = SourceLocation();
// Attributes are only allowed on the second declarator. // Attributes are only allowed on the second declarator.
MaybeParseGNUAttributes(DeclaratorInfo); MaybeParseGNUAttributes(DeclaratorInfo);

View File

@ -677,7 +677,14 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
/// \brief Determine whether the current token, if it occurs after a /// \brief Determine whether the current token, if it occurs after a
/// declarator, continues a declaration or declaration list. /// declarator, continues a declaration or declaration list.
bool Parser::isDeclarationAfterDeclarator() const { bool Parser::isDeclarationAfterDeclarator() {
// Check for '= delete' or '= default'
if (getLang().CPlusPlus && Tok.is(tok::equal)) {
const Token &KW = NextToken();
if (KW.is(tok::kw_default) || KW.is(tok::kw_delete))
return false;
}
return Tok.is(tok::equal) || // int X()= -> not a function def return Tok.is(tok::equal) || // int X()= -> not a function def
Tok.is(tok::comma) || // int X(), -> not a function def Tok.is(tok::comma) || // int X(), -> not a function def
Tok.is(tok::semi) || // int X(); -> not a function def Tok.is(tok::semi) || // int X(); -> not a function def
@ -699,6 +706,11 @@ bool Parser::isStartOfFunctionDefinition(const ParsingDeclarator &Declarator) {
Declarator.getFunctionTypeInfo().isKNRPrototype()) Declarator.getFunctionTypeInfo().isKNRPrototype())
return isDeclarationSpecifier(); return isDeclarationSpecifier();
if (getLang().CPlusPlus && Tok.is(tok::equal)) {
const Token &KW = NextToken();
return KW.is(tok::kw_default) || KW.is(tok::kw_delete);
}
return Tok.is(tok::colon) || // X() : Base() {} (used for ctors) return Tok.is(tok::colon) || // X() : Base() {} (used for ctors)
Tok.is(tok::kw_try); // X() try { ... } Tok.is(tok::kw_try); // X() try { ... }
} }
@ -820,6 +832,73 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
if (FTI.isKNRPrototype()) if (FTI.isKNRPrototype())
ParseKNRParamDeclarations(D); ParseKNRParamDeclarations(D);
if (Tok.is(tok::equal)) {
assert(getLang().CPlusPlus && "Only C++ function definitions have '='");
ConsumeToken();
Decl *Decl = 0;
// Here we complete the declaration as if it were normal
switch (TemplateInfo.Kind) {
case ParsedTemplateInfo::NonTemplate:
Decl = Actions.ActOnDeclarator(getCurScope(), D, true);
break;
case ParsedTemplateInfo::Template:
case ParsedTemplateInfo::ExplicitSpecialization:
Decl = Actions.ActOnTemplateDeclarator(getCurScope(),
MultiTemplateParamsArg(Actions,
TemplateInfo.TemplateParams->data(),
TemplateInfo.TemplateParams->size()),
D);
break;
case ParsedTemplateInfo::ExplicitInstantiation: {
DeclResult Result
= Actions.ActOnExplicitInstantiation(getCurScope(),
TemplateInfo.ExternLoc,
TemplateInfo.TemplateLoc,
D);
if (Result.isInvalid()) {
SkipUntil(tok::semi);
return 0;
}
Decl = Result.get();
break;
}
}
bool Delete = false;
SourceLocation KWLoc;
if (Tok.is(tok::kw_delete)) {
if (!getLang().CPlusPlus0x)
Diag(Tok, diag::warn_deleted_function_accepted_as_extension);
KWLoc = ConsumeToken();
Actions.SetDeclDeleted(Decl, KWLoc);
Delete = true;
} else if (Tok.is(tok::kw_default)) {
if (!getLang().CPlusPlus0x)
Diag(Tok, diag::warn_defaulted_function_accepted_as_extension);
KWLoc = ConsumeToken();
Actions.SetDeclDefaulted(Decl, KWLoc);
} else {
llvm_unreachable("function definition after = not 'delete' or 'default'");
}
if (Tok.is(tok::comma)) {
Diag(KWLoc, diag::err_default_delete_in_multiple_declaration)
<< Delete;
SkipUntil(tok::semi);
} else {
ExpectAndConsume(tok::semi, diag::err_expected_semi_after,
Delete ? "delete" : "default", tok::semi);
}
return Decl;
}
// We should have either an opening brace or, in a C++ constructor, // We should have either an opening brace or, in a C++ constructor,
// we may have a colon. // we may have a colon.
if (Tok.isNot(tok::l_brace) && if (Tok.isNot(tok::l_brace) &&

View File

@ -2913,8 +2913,10 @@ static bool RebuildDeclaratorInCurrentInstantiation(Sema &S, Declarator &D,
return false; return false;
} }
Decl *Sema::ActOnDeclarator(Scope *S, Declarator &D) { Decl *Sema::ActOnDeclarator(Scope *S, Declarator &D,
return HandleDeclarator(S, D, MultiTemplateParamsArg(*this), false); bool IsFunctionDefinition) {
return HandleDeclarator(S, D, MultiTemplateParamsArg(*this),
IsFunctionDefinition);
} }
/// DiagnoseClassNameShadow - Implement C++ [class.mem]p13: /// DiagnoseClassNameShadow - Implement C++ [class.mem]p13:
@ -2939,8 +2941,7 @@ bool Sema::DiagnoseClassNameShadow(DeclContext *DC,
Decl *Sema::HandleDeclarator(Scope *S, Declarator &D, Decl *Sema::HandleDeclarator(Scope *S, Declarator &D,
MultiTemplateParamsArg TemplateParamLists, MultiTemplateParamsArg TemplateParamLists,
bool IsFunctionDefinition, bool IsFunctionDefinition) {
SourceLocation DefaultLoc) {
// TODO: consider using NameInfo for diagnostic. // TODO: consider using NameInfo for diagnostic.
DeclarationNameInfo NameInfo = GetNameForDeclarator(D); DeclarationNameInfo NameInfo = GetNameForDeclarator(D);
DeclarationName Name = NameInfo.getName(); DeclarationName Name = NameInfo.getName();
@ -3141,9 +3142,6 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D,
bool Redeclaration = false; bool Redeclaration = false;
if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) { if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) {
if (DefaultLoc.isValid())
Diag(DefaultLoc, diag::err_default_special_members);
if (TemplateParamLists.size()) { if (TemplateParamLists.size()) {
Diag(D.getIdentifierLoc(), diag::err_template_typedef); Diag(D.getIdentifierLoc(), diag::err_template_typedef);
return 0; return 0;
@ -3153,10 +3151,8 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D,
} else if (R->isFunctionType()) { } else if (R->isFunctionType()) {
New = ActOnFunctionDeclarator(S, D, DC, R, TInfo, Previous, New = ActOnFunctionDeclarator(S, D, DC, R, TInfo, Previous,
move(TemplateParamLists), move(TemplateParamLists),
IsFunctionDefinition, Redeclaration, IsFunctionDefinition, Redeclaration);
DefaultLoc);
} else { } else {
assert(!DefaultLoc.isValid() && "We should have caught this in a caller");
New = ActOnVariableDeclarator(S, D, DC, R, TInfo, Previous, New = ActOnVariableDeclarator(S, D, DC, R, TInfo, Previous,
move(TemplateParamLists), move(TemplateParamLists),
Redeclaration); Redeclaration);
@ -4028,8 +4024,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
QualType R, TypeSourceInfo *TInfo, QualType R, TypeSourceInfo *TInfo,
LookupResult &Previous, LookupResult &Previous,
MultiTemplateParamsArg TemplateParamLists, MultiTemplateParamsArg TemplateParamLists,
bool IsFunctionDefinition, bool &Redeclaration, bool IsFunctionDefinition, bool &Redeclaration) {
SourceLocation DefaultLoc) {
assert(R.getTypePtr()->isFunctionType()); assert(R.getTypePtr()->isFunctionType());
// TODO: consider using NameInfo for diagnostic. // TODO: consider using NameInfo for diagnostic.
@ -4086,8 +4081,6 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
bool isFunctionTemplateSpecialization = false; bool isFunctionTemplateSpecialization = false;
if (!getLangOptions().CPlusPlus) { if (!getLangOptions().CPlusPlus) {
assert(!DefaultLoc.isValid() && "Defaulted functions are a C++ feature");
// Determine whether the function was written with a // Determine whether the function was written with a
// prototype. This true when: // prototype. This true when:
// - there is a prototype in the declarator, or // - there is a prototype in the declarator, or
@ -4689,7 +4682,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
} else if (!IsFunctionDefinition && D.getCXXScopeSpec().isSet() && } else if (!IsFunctionDefinition && D.getCXXScopeSpec().isSet() &&
!isFriend && !isFunctionTemplateSpecialization && !isFriend && !isFunctionTemplateSpecialization &&
!isExplicitSpecialization && !DefaultLoc.isValid()) { !isExplicitSpecialization) {
// An out-of-line member function declaration must also be a // An out-of-line member function declaration must also be a
// definition (C++ [dcl.meaning]p1). // definition (C++ [dcl.meaning]p1).
// Note that this is not the case for explicit specializations of // Note that this is not the case for explicit specializations of
@ -4774,16 +4767,6 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
} }
} }
if (DefaultLoc.isValid()) {
CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewFD);
if (MD && getSpecialMember(MD) != CXXInvalid) {
MD->setExplicitlyDefaulted();
MD->setDefaulted();
} else {
Diag(DefaultLoc, diag::err_default_special_members);
}
}
return NewFD; return NewFD;
} }

View File

@ -1025,8 +1025,7 @@ Decl *
Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
MultiTemplateParamsArg TemplateParameterLists, MultiTemplateParamsArg TemplateParameterLists,
ExprTy *BW, const VirtSpecifiers &VS, ExprTy *BW, const VirtSpecifiers &VS,
ExprTy *InitExpr, bool IsDefinition, ExprTy *InitExpr, bool IsDefinition) {
bool Deleted, SourceLocation DefaultLoc) {
const DeclSpec &DS = D.getDeclSpec(); const DeclSpec &DS = D.getDeclSpec();
DeclarationNameInfo NameInfo = GetNameForDeclarator(D); DeclarationNameInfo NameInfo = GetNameForDeclarator(D);
DeclarationName Name = NameInfo.getName(); DeclarationName Name = NameInfo.getName();
@ -1091,9 +1090,6 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
if (isInstField) { if (isInstField) {
CXXScopeSpec &SS = D.getCXXScopeSpec(); CXXScopeSpec &SS = D.getCXXScopeSpec();
if (DefaultLoc.isValid())
Diag(DefaultLoc, diag::err_default_special_members);
if (SS.isSet() && !SS.isInvalid()) { if (SS.isSet() && !SS.isInvalid()) {
// The user provided a superfluous scope specifier inside a class // The user provided a superfluous scope specifier inside a class
// definition: // definition:
@ -1118,8 +1114,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
AS); AS);
assert(Member && "HandleField never returns null"); assert(Member && "HandleField never returns null");
} else { } else {
Member = HandleDeclarator(S, D, move(TemplateParameterLists), IsDefinition, Member = HandleDeclarator(S, D, move(TemplateParameterLists), IsDefinition);
DefaultLoc);
if (!Member) { if (!Member) {
return 0; return 0;
} }
@ -1189,8 +1184,6 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
if (Init) if (Init)
AddInitializerToDecl(Member, Init, false, AddInitializerToDecl(Member, Init, false,
DS.getTypeSpecType() == DeclSpec::TST_auto); DS.getTypeSpecType() == DeclSpec::TST_auto);
if (Deleted) // FIXME: Source location is not very good.
SetDeclDeleted(Member, D.getSourceRange().getBegin());
FinalizeDeclaration(Member); FinalizeDeclaration(Member);
@ -7865,6 +7858,39 @@ void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) {
Fn->setDeletedAsWritten(); Fn->setDeletedAsWritten();
} }
void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) {
CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Dcl);
if (MD) {
CXXSpecialMember Member = getSpecialMember(MD);
if (Member == CXXInvalid) {
Diag(DefaultLoc, diag::err_default_special_members);
return;
}
MD->setDefaulted();
MD->setExplicitlyDefaulted();
// We'll check it when the record is done
if (MD == MD->getCanonicalDecl())
return;
switch (Member) {
case CXXDefaultConstructor: {
CXXConstructorDecl *CD = cast<CXXConstructorDecl>(MD);
CheckExplicitlyDefaultedDefaultConstructor(CD);
DefineImplicitDefaultConstructor(DefaultLoc, CD);
break;
}
default:
// FIXME: Do the rest once we have functions
break;
}
} else {
Diag(DefaultLoc, diag::err_default_special_members);
}
}
static void SearchForReturnInStmt(Sema &Self, Stmt *S) { static void SearchForReturnInStmt(Sema &Self, Stmt *S) {
for (Stmt::child_range CI = S->children(); CI; ++CI) { for (Stmt::child_range CI = S->children(); CI; ++CI) {
Stmt *SubStmt = *CI; Stmt *SubStmt = *CI;