From: Anders Carlsson Date: Fri, 4 Dec 2009 22:33:25 +0000 (+0000) Subject: Diagnose declarations of implicit member functions. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5c478cf2d54157062cd843737324e0d0df03a464;p=clang Diagnose declarations of implicit member functions. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@90605 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index effab5a03e..c5bebcc951 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -762,6 +762,24 @@ struct GNUCompatibleParamWarning { QualType PromotedType; }; + +/// getSpecialMember - get the special member enum for a method. +static Sema::CXXSpecialMember getSpecialMember(ASTContext &Ctx, + const CXXMethodDecl *MD) { + if (const CXXConstructorDecl *Ctor = dyn_cast(MD)) { + if (Ctor->isDefaultConstructor()) + return Sema::CXXDefaultConstructor; + if (Ctor->isCopyConstructor(Ctx)) + return Sema::CXXCopyConstructor; + } + + if (isa(MD)) + return Sema::CXXDestructor; + + assert(MD->isCopyAssignment() && "Must have copy assignment operator"); + return Sema::CXXCopyAssignment; +} + /// MergeFunctionDecl - We just parsed a function 'New' from /// declarator D which has the same name and scope as a previous /// declaration 'Old'. Figure out how to resolve this situation, @@ -827,33 +845,45 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { const CXXMethodDecl* OldMethod = dyn_cast(Old); const CXXMethodDecl* NewMethod = dyn_cast(New); - if (OldMethod && NewMethod && !NewMethod->getFriendObjectKind() && - NewMethod->getLexicalDeclContext()->isRecord()) { - // -- Member function declarations with the same name and the - // same parameter types cannot be overloaded if any of them - // is a static member function declaration. - if (OldMethod->isStatic() || NewMethod->isStatic()) { - Diag(New->getLocation(), diag::err_ovl_static_nonstatic_member); + if (OldMethod && NewMethod) { + if (!NewMethod->getFriendObjectKind() && + NewMethod->getLexicalDeclContext()->isRecord()) { + // -- Member function declarations with the same name and the + // same parameter types cannot be overloaded if any of them + // is a static member function declaration. + if (OldMethod->isStatic() || NewMethod->isStatic()) { + Diag(New->getLocation(), diag::err_ovl_static_nonstatic_member); + Diag(Old->getLocation(), PrevDiag) << Old << Old->getType(); + return true; + } + + // C++ [class.mem]p1: + // [...] A member shall not be declared twice in the + // member-specification, except that a nested class or member + // class template can be declared and then later defined. + unsigned NewDiag; + if (isa(OldMethod)) + NewDiag = diag::err_constructor_redeclared; + else if (isa(NewMethod)) + NewDiag = diag::err_destructor_redeclared; + else if (isa(NewMethod)) + NewDiag = diag::err_conv_function_redeclared; + else + NewDiag = diag::err_member_redeclared; + + Diag(New->getLocation(), NewDiag); Diag(Old->getLocation(), PrevDiag) << Old << Old->getType(); - return true; + } else { + if (OldMethod->isImplicit()) { + Diag(NewMethod->getLocation(), + diag::err_definition_of_implicitly_declared_member) + << New << getSpecialMember(Context, OldMethod); + + Diag(OldMethod->getLocation(), + diag::note_previous_implicit_declaration); + return true; + } } - - // C++ [class.mem]p1: - // [...] A member shall not be declared twice in the - // member-specification, except that a nested class or member - // class template can be declared and then later defined. - unsigned NewDiag; - if (isa(OldMethod)) - NewDiag = diag::err_constructor_redeclared; - else if (isa(NewMethod)) - NewDiag = diag::err_destructor_redeclared; - else if (isa(NewMethod)) - NewDiag = diag::err_conv_function_redeclared; - else - NewDiag = diag::err_member_redeclared; - - Diag(New->getLocation(), NewDiag); - Diag(Old->getLocation(), PrevDiag) << Old << Old->getType(); } // (C++98 8.3.5p3): diff --git a/test/CodeGenCXX/mangle.cpp b/test/CodeGenCXX/mangle.cpp index 03e405ecba..38f3c8bd3f 100644 --- a/test/CodeGenCXX/mangle.cpp +++ b/test/CodeGenCXX/mangle.cpp @@ -208,8 +208,9 @@ void extern_f(void); void extern_f(void) { } struct S7 { - struct S { S(); }; + S7(); + struct S { S(); }; struct { S s; } a; diff --git a/test/SemaCXX/implicit-member-functions.cpp b/test/SemaCXX/implicit-member-functions.cpp new file mode 100644 index 0000000000..186780833d --- /dev/null +++ b/test/SemaCXX/implicit-member-functions.cpp @@ -0,0 +1,14 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +struct A { }; // expected-note {{previous implicit declaration is here}} +A::A() { } // expected-error {{definition of implicitly declared constructor}} + +struct B { }; // expected-note {{previous implicit declaration is here}} +B::B(const B&) { } // expected-error {{definition of implicitly declared copy constructor}} + +struct C { }; // expected-note {{previous implicit declaration is here}} +C& C::operator=(const C&) { return *this; } // expected-error {{definition of implicitly declared copy assignment operator}} + +struct D { }; // expected-note {{previous implicit declaration is here}} +D::~D() { } // expected-error {{definition of implicitly declared destructor}} +