diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index 88f473eb48b2..f5026f5c4b49 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -1501,6 +1501,9 @@ class CXXConstructorDecl : public CXXMethodDecl { /// @c !Implicit && ImplicitlyDefined. bool ImplicitlyDefined : 1; + /// IsDefaulted - Whether this constructor was explicitly defaulted + bool ExplicitlyDefaulted : 1; + /// Support for base and member initializers. /// CtorInitializers - The arguments used to initialize the base /// or member. @@ -1511,11 +1514,13 @@ class CXXConstructorDecl : public CXXMethodDecl { const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, bool isExplicitSpecified, bool isInline, - bool isImplicitlyDeclared) + bool isImplicitlyDeclared, bool isExplicitlyDefaulted) : CXXMethodDecl(CXXConstructor, RD, StartLoc, NameInfo, T, TInfo, false, SC_None, isInline, SourceLocation()), IsExplicitSpecified(isExplicitSpecified), ImplicitlyDefined(false), - CtorInitializers(0), NumCtorInitializers(0) { + ExplicitlyDefaulted(isExplicitlyDefaulted), + CtorInitializers(0), NumCtorInitializers(0) + { setImplicit(isImplicitlyDeclared); } @@ -1526,7 +1531,8 @@ public: const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, bool isExplicit, - bool isInline, bool isImplicitlyDeclared); + bool isInline, bool isImplicitlyDeclared, + bool isExplicitlyDefaulted); /// isExplicitSpecified - Whether this constructor declaration has the /// 'explicit' keyword specified. @@ -1558,6 +1564,28 @@ public: ImplicitlyDefined = ID; } + /// isExplicitlyDefaulted - Whether this constructor was explicitly defaulted. + bool isExplicitlyDefaulted() const { + return ExplicitlyDefaulted; + } + /// setExplicitlyDefaulted - Set whether this contructor was explicitly + /// defaulted or not. + void setExplicitlyDefaulted(bool B) { + ExplicitlyDefaulted = B; + } + + /// isDefaulted - True if this was either explicitly defaulted or is implicit + bool isDefaulted() const { + return ExplicitlyDefaulted || isImplicit(); + } + + /// isUserProvided - True if this function was neither defaulted nor deleted + /// on its first declaration. + bool isUserProvided() const { + const CXXConstructorDecl *Canonical = getCanonicalDecl(); + return !Canonical->isDefaulted() && !Canonical->isDeleted(); + } + /// init_iterator - Iterates through the member/base initializer list. typedef CXXCtorInitializer **init_iterator; diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td b/clang/include/clang/Basic/DiagnosticCommonKinds.td index 0b0bca0395cb..166f81a5ffe1 100644 --- a/clang/include/clang/Basic/DiagnosticCommonKinds.td +++ b/clang/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/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index c37e510b3479..e2ffe109c822 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/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/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index b528042345f7..fee483b7f901 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -3057,7 +3057,7 @@ public: MultiTemplateParamsArg TemplateParameterLists, Expr *BitfieldWidth, const VirtSpecifiers &VS, Expr *Init, bool IsDefinition, - bool Deleted = false); + bool Deleted = false, bool Defaulted = false); MemInitResult ActOnMemInitializer(Decl *ConstructorD, Scope *S, diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index dc881ba86960..8e95cfecf4cf 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -2397,7 +2397,8 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { NameInfo, T, TInfo, FromConstructor->isExplicit(), D->isInlineSpecified(), - D->isImplicit()); + D->isImplicit(), + FromConstructor->isExplicitlyDefaulted()); } else if (isa(D)) { ToFunction = CXXDestructorDecl::Create(Importer.getToContext(), cast(DC), diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index 9099cd524f1a..ce2d81192994 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -1301,7 +1301,7 @@ SourceRange CXXCtorInitializer::getSourceRange() const { CXXConstructorDecl * CXXConstructorDecl::Create(ASTContext &C, EmptyShell Empty) { return new (C) CXXConstructorDecl(0, SourceLocation(), DeclarationNameInfo(), - QualType(), 0, false, false, false); + QualType(), 0, false, false, false, false); } CXXConstructorDecl * @@ -1311,12 +1311,14 @@ CXXConstructorDecl::Create(ASTContext &C, CXXRecordDecl *RD, QualType T, TypeSourceInfo *TInfo, bool isExplicit, bool isInline, - bool isImplicitlyDeclared) { + bool isImplicitlyDeclared, + bool isExplicitlyDefaulted) { assert(NameInfo.getName().getNameKind() == DeclarationName::CXXConstructorName && "Name must refer to a constructor"); return new (C) CXXConstructorDecl(RD, StartLoc, NameInfo, T, TInfo, - isExplicit, isInline, isImplicitlyDeclared); + isExplicit, isInline, isImplicitlyDeclared, + isExplicitlyDefaulted); } bool CXXConstructorDecl::isDefaultConstructor() const { diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index a20e90bd0ea3..1eaae678e2ff 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -966,6 +966,11 @@ 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); + + ThisDecl->setInvalidDecl(); } else { if (getLang().CPlusPlus && D.getCXXScopeSpec().isSet()) { EnterScope(0); diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 596778dbd320..41b773e00744 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -1621,6 +1621,8 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, ExprResult BitfieldSize; ExprResult Init; bool Deleted = false; + bool Defaulted = false; + SourceLocation DefLoc; while (1) { // member-declarator: @@ -1652,6 +1654,11 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, Diag(Tok, diag::warn_deleted_function_accepted_as_extension); ConsumeToken(); Deleted = true; + } else if (Tok.is(tok::kw_delete)) { + if (!getLang().CPlusPlus0x) + Diag(Tok, diag::warn_defaulted_function_accepted_as_extension); + DefLoc = ConsumeToken(); + Defaulted = true; } else { Init = ParseInitializer(); if (Init.isInvalid()) @@ -1683,6 +1690,10 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, ThisDecl = Actions.ActOnFriendFunctionDecl(getCurScope(), DeclaratorInfo, /*IsDefinition*/ false, move(TemplateParams)); + if (Defaulted) { + Diag(DefLoc, diag::err_friends_define_only_namespace_scope); + ThisDecl->setInvalidDecl(); + } } else { ThisDecl = Actions.ActOnCXXMemberDeclarator(getCurScope(), AS, DeclaratorInfo, @@ -1690,7 +1701,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, BitfieldSize.release(), VS, Init.release(), /*IsDefinition*/Deleted, - Deleted); + Deleted, Defaulted); } if (ThisDecl) DeclsInGroup.push_back(ThisDecl); @@ -1717,6 +1728,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, BitfieldSize = 0; Init = 0; Deleted = false; + Defaulted = false; // Attributes are only allowed on the second declarator. MaybeParseGNUAttributes(DeclaratorInfo); diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index d5112a2f0cc9..6231fbd11179 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -4103,7 +4103,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, D.getSourceRange().getBegin(), NameInfo, R, TInfo, isExplicit, isInline, - /*isImplicitlyDeclared=*/false); + /*isImplicitlyDeclared=*/false, + /*isExplicitlyDefaulted=*/false); } else if (Name.getNameKind() == DeclarationName::CXXDestructorName) { // This is a C++ destructor declaration. if (DC->isRecord()) { diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 7b2869681445..2ef15b672d3e 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -963,7 +963,10 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, MultiTemplateParamsArg TemplateParameterLists, ExprTy *BW, const VirtSpecifiers &VS, ExprTy *InitExpr, bool IsDefinition, - bool Deleted) { + bool Deleted, bool Defaulted) { + // FIXME: Do something with this + (void) Defaulted; + const DeclSpec &DS = D.getDeclSpec(); DeclarationNameInfo NameInfo = GetNameForDeclarator(D); DeclarationName Name = NameInfo.getName(); @@ -4956,7 +4959,8 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( /*TInfo=*/0, /*isExplicit=*/false, /*isInline=*/true, - /*isImplicitlyDeclared=*/true); + /*isImplicitlyDeclared=*/true, + /*isExplicitlyDefaulted=*/false); DefaultCon->setAccess(AS_public); DefaultCon->setImplicit(); DefaultCon->setTrivial(ClassDecl->hasTrivialConstructor()); @@ -5152,7 +5156,8 @@ void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) { CXXConstructorDecl *NewCtor = CXXConstructorDecl::Create( Context, ClassDecl, UsingLoc, DNI, QualType(NewCtorType, 0), /*TInfo=*/0, BaseCtor->isExplicit(), /*Inline=*/true, - /*ImplicitlyDeclared=*/true); + /*ImplicitlyDeclared=*/true, + /*isExplicitlyDefaulted*/false); NewCtor->setAccess(BaseCtor->getAccess()); // Build up the parameter decls and add them. @@ -6101,7 +6106,8 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( /*TInfo=*/0, /*isExplicit=*/false, /*isInline=*/true, - /*isImplicitlyDeclared=*/true); + /*isImplicitlyDeclared=*/true, + /*isExplicitlyDefaulted=*/false); CopyConstructor->setAccess(AS_public); CopyConstructor->setTrivial(ClassDecl->hasTrivialCopyConstructor()); diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 6e11ef5bbc5f..6fa208f6f85c 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1330,7 +1330,8 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, StartLoc, NameInfo, T, TInfo, Constructor->isExplicit(), Constructor->isInlineSpecified(), - false); + false, + Constructor->isExplicitlyDefaulted()); } else if (CXXDestructorDecl *Destructor = dyn_cast(D)) { Method = CXXDestructorDecl::Create(SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo,