]> granicus.if.org Git - clang/commitdiff
Diagnose declarations of implicit member functions.
authorAnders Carlsson <andersca@mac.com>
Fri, 4 Dec 2009 22:33:25 +0000 (22:33 +0000)
committerAnders Carlsson <andersca@mac.com>
Fri, 4 Dec 2009 22:33:25 +0000 (22:33 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@90605 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaDecl.cpp
test/CodeGenCXX/mangle.cpp
test/SemaCXX/implicit-member-functions.cpp [new file with mode: 0644]

index effab5a03ebff30aa9b3a169565e8f0ea13a59af..c5bebcc9516da7b2e3fea9f1648498e04162259a 100644 (file)
@@ -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<CXXConstructorDecl>(MD)) {
+    if (Ctor->isDefaultConstructor())
+      return Sema::CXXDefaultConstructor;
+    if (Ctor->isCopyConstructor(Ctx))
+      return Sema::CXXCopyConstructor;
+  } 
+  
+  if (isa<CXXDestructorDecl>(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<CXXMethodDecl>(Old);
     const CXXMethodDecl* NewMethod = dyn_cast<CXXMethodDecl>(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<CXXConstructorDecl>(OldMethod))
+          NewDiag = diag::err_constructor_redeclared;
+        else if (isa<CXXDestructorDecl>(NewMethod))
+          NewDiag = diag::err_destructor_redeclared;
+        else if (isa<CXXConversionDecl>(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<CXXConstructorDecl>(OldMethod))
-        NewDiag = diag::err_constructor_redeclared;
-      else if (isa<CXXDestructorDecl>(NewMethod))
-        NewDiag = diag::err_destructor_redeclared;
-      else if (isa<CXXConversionDecl>(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):
index 03e405ecba1d05c57df9fba7f0a4f6f7afefec20..38f3c8bd3fb364ff8ee297e8dd260976249566cf 100644 (file)
@@ -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 (file)
index 0000000..1867808
--- /dev/null
@@ -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}}
+