diff options
-rw-r--r-- | include/clang/AST/Decl.h | 12 | ||||
-rw-r--r-- | include/clang/AST/DeclCXX.h | 6 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticCommonKinds.td | 4 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticParseKinds.td | 3 | ||||
-rw-r--r-- | include/clang/Sema/Sema.h | 9 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 4 | ||||
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 11 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 63 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 7 |
9 files changed, 103 insertions, 16 deletions
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index ef49205203..2cf2618491 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -1365,6 +1365,8 @@ private: bool HasWrittenPrototype : 1; bool IsDeleted : 1; bool IsTrivial : 1; // sunk from CXXMethodDecl + bool IsDefaulted : 1; // sunk from CXXMethoDecl + bool IsExplicitlyDefaulted : 1; //sunk from CXXMethodDecl bool HasImplicitReturnZero : 1; bool IsLateTemplateParsed : 1; @@ -1566,6 +1568,16 @@ public: bool isTrivial() const { return IsTrivial; } void setTrivial(bool IT) { IsTrivial = IT; } + /// Whether this function is defaulted per C++0x. Only valid for + /// special member functions. + bool isDefaulted() const { return IsDefaulted; } + void setDefaulted(bool D = true) { IsDefaulted = D; } + + /// Whether this function is explicitly defaulted per C++0x. Only valid + /// for special member functions. + bool isExplicitlyDefaulted() const { return IsExplicitlyDefaulted; } + void setExplicitlyDefaulted(bool ED = true) { IsExplicitlyDefaulted = ED; } + /// Whether falling off this function implicitly returns null/zero. /// If a more specific implicit return value is required, front-ends /// should synthesize the appropriate return statements. diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index 88f473eb48..25a75b9ea0 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -1189,6 +1189,12 @@ public: CXXMethodDecl *getCanonicalDecl() { return cast<CXXMethodDecl>(FunctionDecl::getCanonicalDecl()); } + + /// isUserProvided - True if it is either an implicit constructor or + /// if it was defaulted or deleted on first declaration. + bool isUserProvided() const { + return getCanonicalDecl()->isDeleted() || getCanonicalDecl()->isDefaulted(); + } /// void addOverriddenMethod(const CXXMethodDecl *MD); diff --git a/include/clang/Basic/DiagnosticCommonKinds.td b/include/clang/Basic/DiagnosticCommonKinds.td index 0b0bca0395..166f81a5ff 100644 --- a/include/clang/Basic/DiagnosticCommonKinds.td +++ b/include/clang/Basic/DiagnosticCommonKinds.td @@ -52,6 +52,10 @@ def err_invalid_storage_class_in_func_decl : Error< def err_expected_namespace_name : Error<"expected namespace name">; def ext_variadic_templates : ExtWarn< "variadic templates are a C++0x extension">, InGroup<CXX0x>; +def err_default_special_members : Error< + "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">; // Sema && Lex def ext_longlong : Extension< diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index e2d7f4ce9a..3a8a708afa 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -434,6 +434,9 @@ def err_missing_whitespace_digraph : Error< def warn_deleted_function_accepted_as_extension: ExtWarn< "deleted function definition accepted as a C++0x extension">, InGroup<CXX0x>; +def warn_defaulted_function_accepted_as_extension: ExtWarn< + "defaulted function definition accepted as a C++0x extension">, + InGroup<CXX0x>; // C++0x alias-declaration def ext_alias_declaration : ExtWarn< diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 69e14f3c0b..1ce7f6af5b 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -935,7 +935,8 @@ public: Decl *HandleDeclarator(Scope *S, Declarator &D, MultiTemplateParamsArg TemplateParameterLists, - bool IsFunctionDefinition); + bool IsFunctionDefinition, + SourceLocation DefLoc = SourceLocation()); void RegisterLocallyScopedExternCDecl(NamedDecl *ND, const LookupResult &Previous, Scope *S); @@ -963,7 +964,8 @@ public: LookupResult &Previous, MultiTemplateParamsArg TemplateParamLists, bool IsFunctionDefinition, - bool &Redeclaration); + bool &Redeclaration, + SourceLocation DefLoc = SourceLocation()); bool AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD); void DiagnoseHiddenVirtualMethods(CXXRecordDecl *DC, CXXMethodDecl *MD); void CheckFunctionDeclaration(Scope *S, @@ -3063,7 +3065,8 @@ public: MultiTemplateParamsArg TemplateParameterLists, Expr *BitfieldWidth, const VirtSpecifiers &VS, Expr *Init, bool IsDefinition, - bool Deleted = false); + bool Deleted = false, + SourceLocation DefLoc = SourceLocation()); MemInitResult ActOnMemInitializer(Decl *ConstructorD, Scope *S, diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index a20e90bd0e..a4c323979d 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -966,6 +966,10 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, Diag(DelLoc, diag::warn_deleted_function_accepted_as_extension); Actions.SetDeclDeleted(ThisDecl, DelLoc); + } else if (Tok.is(tok::kw_default)) { + SourceLocation DefLoc = ConsumeToken(); + + Diag(DefLoc, diag::err_default_special_members); } else { if (getLang().CPlusPlus && D.getCXXScopeSpec().isSet()) { EnterScope(0); diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 7247c0724e..d263f96e26 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -1648,6 +1648,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, ExprResult BitfieldSize; ExprResult Init; bool Deleted = false; + SourceLocation DefLoc; while (1) { // member-declarator: @@ -1679,6 +1680,10 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, Diag(Tok, diag::warn_deleted_function_accepted_as_extension); ConsumeToken(); Deleted = true; + } else if (Tok.is(tok::kw_default)) { + if (!getLang().CPlusPlus0x) + Diag(Tok, diag::warn_defaulted_function_accepted_as_extension); + DefLoc = ConsumeToken(); } else { Init = ParseInitializer(); if (Init.isInvalid()) @@ -1706,6 +1711,9 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, Decl *ThisDecl = 0; if (DS.isFriendSpecified()) { + if (DefLoc.isValid()) + Diag(DefLoc, diag::err_default_special_members); + // TODO: handle initializers, bitfields, 'delete' ThisDecl = Actions.ActOnFriendFunctionDecl(getCurScope(), DeclaratorInfo, /*IsDefinition*/ false, @@ -1717,7 +1725,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, BitfieldSize.release(), VS, Init.release(), /*IsDefinition*/Deleted, - Deleted); + Deleted, DefLoc); } if (ThisDecl) DeclsInGroup.push_back(ThisDecl); @@ -1744,6 +1752,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, BitfieldSize = 0; Init = 0; Deleted = false; + DefLoc = SourceLocation(); // Attributes are only allowed on the second declarator. MaybeParseGNUAttributes(DeclaratorInfo); diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 2a63c91135..0bf984d40a 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -2919,7 +2919,8 @@ bool Sema::DiagnoseClassNameShadow(DeclContext *DC, Decl *Sema::HandleDeclarator(Scope *S, Declarator &D, MultiTemplateParamsArg TemplateParamLists, - bool IsFunctionDefinition) { + bool IsFunctionDefinition, + SourceLocation DefLoc) { // TODO: consider using NameInfo for diagnostic. DeclarationNameInfo NameInfo = GetNameForDeclarator(D); DeclarationName Name = NameInfo.getName(); @@ -2962,7 +2963,6 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D, << D.getCXXScopeSpec().getRange(); return 0; } - bool IsDependentContext = DC->isDependentContext(); if (!IsDependentContext && @@ -3121,6 +3121,9 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D, bool Redeclaration = false; if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) { + if (DefLoc.isValid()) + Diag(DefLoc, diag::err_default_special_members); + if (TemplateParamLists.size()) { Diag(D.getIdentifierLoc(), diag::err_template_typedef); return 0; @@ -3130,8 +3133,9 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D, } else if (R->isFunctionType()) { New = ActOnFunctionDeclarator(S, D, DC, R, TInfo, Previous, move(TemplateParamLists), - IsFunctionDefinition, Redeclaration); + IsFunctionDefinition, Redeclaration, DefLoc); } else { + assert(!DefLoc.isValid() && "We should have caught this in a caller"); New = ActOnVariableDeclarator(S, D, DC, R, TInfo, Previous, move(TemplateParamLists), Redeclaration); @@ -4003,7 +4007,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, QualType R, TypeSourceInfo *TInfo, LookupResult &Previous, MultiTemplateParamsArg TemplateParamLists, - bool IsFunctionDefinition, bool &Redeclaration) { + bool IsFunctionDefinition, bool &Redeclaration, + SourceLocation DefLoc) { assert(R.getTypePtr()->isFunctionType()); // TODO: consider using NameInfo for diagnostic. @@ -4060,6 +4065,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, bool isFunctionTemplateSpecialization = false; if (!getLangOptions().CPlusPlus) { + assert(!DefLoc.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 @@ -4104,12 +4111,25 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, R = CheckConstructorDeclarator(D, R, SC); // Create the new declaration - NewFD = CXXConstructorDecl::Create(Context, + CXXConstructorDecl *NewCD = CXXConstructorDecl::Create( + Context, cast<CXXRecordDecl>(DC), D.getSourceRange().getBegin(), NameInfo, R, TInfo, isExplicit, isInline, /*isImplicitlyDeclared=*/false); + + NewFD = NewCD; + + if (DefLoc.isValid()) { + if (NewCD->isDefaultConstructor() || + NewCD->isCopyOrMoveConstructor()) { + NewFD->setDefaulted(); + NewFD->setExplicitlyDefaulted(); + } else { + Diag(DefLoc, diag::err_default_special_members); + } + } } else if (Name.getNameKind() == DeclarationName::CXXDestructorName) { // This is a C++ destructor declaration. if (DC->isRecord()) { @@ -4122,6 +4142,11 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, isInline, /*isImplicitlyDeclared=*/false); isVirtualOkay = true; + + if (DefLoc.isValid()) { + NewFD->setDefaulted(); + NewFD->setExplicitlyDefaulted(); + } } else { Diag(D.getIdentifierLoc(), diag::err_destructor_not_member); @@ -4140,6 +4165,9 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, return 0; } + if (DefLoc.isValid()) + Diag(DefLoc, diag::err_default_special_members); + CheckConversionDeclarator(D, R, SC); NewFD = CXXConversionDecl::Create(Context, cast<CXXRecordDecl>(DC), D.getSourceRange().getBegin(), @@ -4178,14 +4206,29 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, isStatic = true; // This is a C++ method declaration. - NewFD = CXXMethodDecl::Create(Context, cast<CXXRecordDecl>(DC), - D.getSourceRange().getBegin(), - NameInfo, R, TInfo, - isStatic, SCAsWritten, isInline, - SourceLocation()); + CXXMethodDecl *NewMD = CXXMethodDecl::Create( + Context, cast<CXXRecordDecl>(DC), + D.getSourceRange().getBegin(), + NameInfo, R, TInfo, + isStatic, SCAsWritten, isInline, + SourceLocation()); + NewFD = NewMD; isVirtualOkay = !isStatic; + + if (DefLoc.isValid()) { + if (NewMD->isCopyAssignmentOperator() /* || + NewMD->isMoveAssignmentOperator() */) { + NewFD->setDefaulted(); + NewFD->setExplicitlyDefaulted(); + } else { + Diag(DefLoc, diag::err_default_special_members); + } + } } else { + if (DefLoc.isValid()) + Diag(DefLoc, diag::err_default_special_members); + // Determine whether the function was written with a // prototype. This true when: // - we're in C++ (where every function has a prototype), diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 525cb81c80..ca5fdd1fdd 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -963,7 +963,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, MultiTemplateParamsArg TemplateParameterLists, ExprTy *BW, const VirtSpecifiers &VS, ExprTy *InitExpr, bool IsDefinition, - bool Deleted) { + bool Deleted, SourceLocation DefLoc) { const DeclSpec &DS = D.getDeclSpec(); DeclarationNameInfo NameInfo = GetNameForDeclarator(D); DeclarationName Name = NameInfo.getName(); @@ -1028,6 +1028,8 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, if (isInstField) { CXXScopeSpec &SS = D.getCXXScopeSpec(); + if (DefLoc.isValid()) + Diag(DefLoc, diag::err_default_special_members); if (SS.isSet() && !SS.isInvalid()) { // The user provided a superfluous scope specifier inside a class @@ -1053,7 +1055,8 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, AS); assert(Member && "HandleField never returns null"); } else { - Member = HandleDeclarator(S, D, move(TemplateParameterLists), IsDefinition); + Member = HandleDeclarator(S, D, move(TemplateParameterLists), IsDefinition, + DefLoc); if (!Member) { return 0; } |