"only special member functions may be defaulted">;
def err_friends_define_only_namespace_scope : Error<
"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
def ext_longlong : Extension<
// Classes.
def err_anon_type_definition : Error<
"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<
"C++0x attribute '%0' cannot have an argument list">;
def note_pure_virtual_function : Note<
"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<
"deleted definition must be first declaration">;
DeclGroupPtrTy ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
ParsingDeclSpec *DS = 0);
- bool isDeclarationAfterDeclarator() const;
+ bool isDeclarationAfterDeclarator();
bool isStartOfFunctionDefinition(const ParsingDeclarator &Declarator);
DeclGroupPtrTy ParseDeclarationOrFunctionDefinition(ParsedAttributes &attrs,
AccessSpecifier AS = AS_none);
SourceLocation NameLoc,
const Token &NextToken);
- Decl *ActOnDeclarator(Scope *S, Declarator &D);
+ Decl *ActOnDeclarator(Scope *S, Declarator &D,
+ bool IsFunctionDefintion = false);
Decl *HandleDeclarator(Scope *S, Declarator &D,
MultiTemplateParamsArg TemplateParameterLists,
- bool IsFunctionDefinition,
- SourceLocation DefaultLoc = SourceLocation());
+ bool IsFunctionDefinition);
void RegisterLocallyScopedExternCDecl(NamedDecl *ND,
const LookupResult &Previous,
Scope *S);
LookupResult &Previous,
MultiTemplateParamsArg TemplateParamLists,
bool IsFunctionDefinition,
- bool &Redeclaration,
- SourceLocation DefaultLoc = SourceLocation());
+ bool &Redeclaration);
bool AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD);
void DiagnoseHiddenVirtualMethods(CXXRecordDecl *DC, CXXMethodDecl *MD);
void CheckFunctionDeclaration(Scope *S,
void ActOnInitializerError(Decl *Dcl);
void ActOnCXXForRangeDecl(Decl *D);
void SetDeclDeleted(Decl *dcl, SourceLocation DelLoc);
+ void SetDeclDefaulted(Decl *dcl, SourceLocation DefaultLoc);
void FinalizeDeclaration(Decl *D);
DeclGroupPtrTy FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
Decl **Group,
Declarator &D,
MultiTemplateParamsArg TemplateParameterLists,
Expr *BitfieldWidth, const VirtSpecifiers &VS,
- Expr *Init, bool IsDefinition,
- bool Deleted = false,
- SourceLocation DefaultLoc = SourceLocation());
+ Expr *Init, bool IsDefinition);
MemInitResult ActOnMemInitializer(Decl *ConstructorD,
Scope *S,
const ParsedTemplateInfo &TemplateInfo,
const VirtSpecifiers& VS, ExprResult& Init) {
assert(D.isFunctionDeclarator() && "This isn't a function declarator!");
- assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try)) &&
- "Current token not a '{', ':' or 'try'!");
+ assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try) ||
+ Tok.is(tok::equal)) &&
+ "Current token not a '{', ':', '=', or 'try'!");
MultiTemplateParamsArg TemplateParams(Actions,
TemplateInfo.TemplateParams ? TemplateInfo.TemplateParams->data() : 0,
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
// 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.
diag::err_invalid_equalequal_after_declarator)) {
ConsumeToken();
if (Tok.is(tok::kw_delete)) {
- SourceLocation DelLoc = ConsumeToken();
-
- if (!getLang().CPlusPlus0x)
- Diag(DelLoc, diag::warn_deleted_function_accepted_as_extension);
-
- Actions.SetDeclDeleted(ThisDecl, DelLoc);
+ if (D.isFunctionDeclarator())
+ Diag(ConsumeToken(), diag::err_default_delete_in_multiple_declaration)
+ << 1 /* delete */;
+ else
+ Diag(ConsumeToken(), diag::err_deleted_non_function);
} else if (Tok.is(tok::kw_default)) {
- Diag(ConsumeToken(), diag::err_default_special_members);
+ if (D.isFunctionDeclarator())
+ Diag(Tok, diag::err_default_delete_in_multiple_declaration)
+ << 1 /* delete */;
+ else
+ Diag(ConsumeToken(), diag::err_default_special_members);
} else {
if (getLang().CPlusPlus && D.getCXXScopeSpec().isSet()) {
EnterScope(0);
SkipUntil(tok::comma, true, true);
}
+ bool IsDefinition = false;
// function-definition:
- if (Tok.is(tok::l_brace)
- || (DeclaratorInfo.isFunctionDeclarator() &&
- (Tok.is(tok::colon) || Tok.is(tok::kw_try)))) {
+ if (Tok.is(tok::l_brace)) {
+ IsDefinition = true;
+ } 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()) {
Diag(Tok, diag::err_func_def_no_params);
ConsumeBrace();
}
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();
+ }
return;
}
llvm::SmallVector<Decl *, 8> DeclsInGroup;
ExprResult BitfieldSize;
- bool Deleted = false;
- SourceLocation DefaultLoc;
while (1) {
// member-declarator:
if (Tok.is(tok::equal)) {
ConsumeToken();
if (Tok.is(tok::kw_delete)) {
- if (!getLang().CPlusPlus0x)
- Diag(Tok, diag::warn_deleted_function_accepted_as_extension);
- ConsumeToken();
- Deleted = true;
+ if (DeclaratorInfo.isFunctionDeclarator())
+ Diag(ConsumeToken(), diag::err_default_delete_in_multiple_declaration)
+ << 1 /* delete */;
+ else
+ Diag(ConsumeToken(), diag::err_deleted_non_function);
} else if (Tok.is(tok::kw_default)) {
- if (!getLang().CPlusPlus0x)
- Diag(Tok, diag::warn_defaulted_function_accepted_as_extension);
- DefaultLoc = ConsumeToken();
+ if (DeclaratorInfo.isFunctionDeclarator())
+ Diag(Tok, diag::err_default_delete_in_multiple_declaration)
+ << 1 /* delete */;
+ else
+ Diag(ConsumeToken(), diag::err_default_special_members);
} else {
Init = ParseInitializer();
if (Init.isInvalid())
Decl *ThisDecl = 0;
if (DS.isFriendSpecified()) {
- if (DefaultLoc.isValid())
- Diag(DefaultLoc, diag::err_default_special_members);
-
// TODO: handle initializers, bitfields, 'delete'
ThisDecl = Actions.ActOnFriendFunctionDecl(getCurScope(), DeclaratorInfo,
/*IsDefinition*/ false,
DeclaratorInfo,
move(TemplateParams),
BitfieldSize.release(),
- VS, Init.release(),
- /*IsDefinition*/Deleted,
- Deleted, DefaultLoc);
+ VS, Init.release(), false);
}
if (ThisDecl)
DeclsInGroup.push_back(ThisDecl);
VS.clear();
BitfieldSize = 0;
Init = 0;
- Deleted = false;
- DefaultLoc = SourceLocation();
// Attributes are only allowed on the second declarator.
MaybeParseGNUAttributes(DeclaratorInfo);
/// \brief Determine whether the current token, if it occurs after a
/// 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
Tok.is(tok::comma) || // int X(), -> not a function def
Tok.is(tok::semi) || // int X(); -> not a function def
if (!getLang().CPlusPlus &&
Declarator.getFunctionTypeInfo().isKNRPrototype())
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)
Tok.is(tok::kw_try); // X() try { ... }
if (FTI.isKNRPrototype())
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 may have a colon.
if (Tok.isNot(tok::l_brace) &&
return false;
}
-Decl *Sema::ActOnDeclarator(Scope *S, Declarator &D) {
- return HandleDeclarator(S, D, MultiTemplateParamsArg(*this), false);
+Decl *Sema::ActOnDeclarator(Scope *S, Declarator &D,
+ bool IsFunctionDefinition) {
+ return HandleDeclarator(S, D, MultiTemplateParamsArg(*this),
+ IsFunctionDefinition);
}
/// DiagnoseClassNameShadow - Implement C++ [class.mem]p13:
Decl *Sema::HandleDeclarator(Scope *S, Declarator &D,
MultiTemplateParamsArg TemplateParamLists,
- bool IsFunctionDefinition,
- SourceLocation DefaultLoc) {
+ bool IsFunctionDefinition) {
// TODO: consider using NameInfo for diagnostic.
DeclarationNameInfo NameInfo = GetNameForDeclarator(D);
DeclarationName Name = NameInfo.getName();
bool Redeclaration = false;
if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) {
- if (DefaultLoc.isValid())
- Diag(DefaultLoc, diag::err_default_special_members);
-
if (TemplateParamLists.size()) {
Diag(D.getIdentifierLoc(), diag::err_template_typedef);
return 0;
} else if (R->isFunctionType()) {
New = ActOnFunctionDeclarator(S, D, DC, R, TInfo, Previous,
move(TemplateParamLists),
- IsFunctionDefinition, Redeclaration,
- DefaultLoc);
+ IsFunctionDefinition, Redeclaration);
} else {
- assert(!DefaultLoc.isValid() && "We should have caught this in a caller");
New = ActOnVariableDeclarator(S, D, DC, R, TInfo, Previous,
move(TemplateParamLists),
Redeclaration);
QualType R, TypeSourceInfo *TInfo,
LookupResult &Previous,
MultiTemplateParamsArg TemplateParamLists,
- bool IsFunctionDefinition, bool &Redeclaration,
- SourceLocation DefaultLoc) {
+ bool IsFunctionDefinition, bool &Redeclaration) {
assert(R.getTypePtr()->isFunctionType());
// TODO: consider using NameInfo for diagnostic.
bool isFunctionTemplateSpecialization = false;
if (!getLangOptions().CPlusPlus) {
- assert(!DefaultLoc.isValid() && "Defaulted functions are a C++ feature");
-
// Determine whether the function was written with a
// prototype. This true when:
// - there is a prototype in the declarator, or
} else if (!IsFunctionDefinition && D.getCXXScopeSpec().isSet() &&
!isFriend && !isFunctionTemplateSpecialization &&
- !isExplicitSpecialization && !DefaultLoc.isValid()) {
+ !isExplicitSpecialization) {
// An out-of-line member function declaration must also be a
// definition (C++ [dcl.meaning]p1).
// Note that this is not the case for explicit specializations of
<< D.getCXXScopeSpec().getRange();
}
}
-
-
+
+
// Handle attributes. We need to have merged decls when handling attributes
// (for example to check for conflicts, etc).
// FIXME: This needs to happen before we merge declarations. Then,
}
}
- 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;
}
Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
MultiTemplateParamsArg TemplateParameterLists,
ExprTy *BW, const VirtSpecifiers &VS,
- ExprTy *InitExpr, bool IsDefinition,
- bool Deleted, SourceLocation DefaultLoc) {
+ ExprTy *InitExpr, bool IsDefinition) {
const DeclSpec &DS = D.getDeclSpec();
DeclarationNameInfo NameInfo = GetNameForDeclarator(D);
DeclarationName Name = NameInfo.getName();
if (isInstField) {
CXXScopeSpec &SS = D.getCXXScopeSpec();
- if (DefaultLoc.isValid())
- Diag(DefaultLoc, diag::err_default_special_members);
-
if (SS.isSet() && !SS.isInvalid()) {
// The user provided a superfluous scope specifier inside a class
// definition:
AS);
assert(Member && "HandleField never returns null");
} else {
- Member = HandleDeclarator(S, D, move(TemplateParameterLists), IsDefinition,
- DefaultLoc);
+ Member = HandleDeclarator(S, D, move(TemplateParameterLists), IsDefinition);
if (!Member) {
return 0;
}
if (Init)
AddInitializerToDecl(Member, Init, false,
DS.getTypeSpecType() == DeclSpec::TST_auto);
- if (Deleted) // FIXME: Source location is not very good.
- SetDeclDeleted(Member, D.getSourceRange().getBegin());
FinalizeDeclaration(Member);
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) {
for (Stmt::child_range CI = S->children(); CI; ++CI) {
Stmt *SubStmt = *CI;