From: Sean Hunt Date: Fri, 6 May 2011 01:42:00 +0000 (+0000) Subject: Do defaulted constructors properly. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=fe2695eec167b28578825576863228f86b392f24;p=clang Do defaulted constructors properly. Explictly defaultedness is correctly reflected on the AST, but there are no changes to how that affects the definition of functions or much else really. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@130974 91177308-0d34-0410-b5e6-96231b3b80d8 --- 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(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; +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; +def warn_defaulted_function_accepted_as_extension: ExtWarn< + "defaulted function definition accepted as a C++0x extension">, + InGroup; // 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(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(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(DC), - D.getSourceRange().getBegin(), - NameInfo, R, TInfo, - isStatic, SCAsWritten, isInline, - SourceLocation()); + CXXMethodDecl *NewMD = CXXMethodDecl::Create( + Context, cast(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; }