]> granicus.if.org Git - clang/commitdiff
Implement a new warning for when adding a default argument to a method
authorSean Hunt <scshunt@csclub.uwaterloo.ca>
Thu, 26 May 2011 01:26:05 +0000 (01:26 +0000)
committerSean Hunt <scshunt@csclub.uwaterloo.ca>
Thu, 26 May 2011 01:26:05 +0000 (01:26 +0000)
makes it into a special member function. This is very bad and can lead
to all sorts of nastiness including implicit member functions violating
the One Definition Rule. This should probably be made ill-formed in a
later version of the standard, but for now we'll just warn.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@132104 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaDecl.cpp
lib/Sema/SemaDeclCXX.cpp
test/SemaCXX/copy-constructor-error.cpp
test/SemaCXX/default-arg-special-member.cpp [new file with mode: 0644]

index f36f3475c1b39eb2f4a979a17bc005d6bd9f7d9e..5e1f3f58188014bb1cac980be10918220aba3bbe 100644 (file)
@@ -1416,6 +1416,13 @@ def note_first_required_here : Note<
 def err_uninitialized_member_in_ctor : Error<
   "%select{|implicit default }0constructor for %1 must explicitly initialize "
   "the %select{reference|const}2 member %3">;
+def warn_default_arg_makes_ctor_special : Warning<
+  "addition of default argument on redeclaration makes this constructor a "
+  "%select{default|copy|move}0 constructor">;
+def note_previous_declaration_special : Note<
+  // The ERRORs are in hopes that if they occur, they'll get reported.
+  "previous declaration was %select{*ERROR*|a copy constructor|a move "
+  "constructor|*ERROR*|*ERROR*|*ERROR*|not a special member function}0">;
 
 def err_use_of_default_argument_to_function_declared_later : Error<
   "use of default argument to function %0 that is declared later in class %1">;
index dae7ba20b1f680b8593ba7223fad4a180d33b7d9..77bd5b79ae03f8c9d6d3a0e5352aa6aa27c62d03 100644 (file)
@@ -1505,14 +1505,14 @@ struct GNUCompatibleParamWarning {
 /// getSpecialMember - get the special member enum for a method.
 Sema::CXXSpecialMember Sema::getSpecialMember(const CXXMethodDecl *MD) {
   if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(MD)) {
+    if (Ctor->isDefaultConstructor())
+      return Sema::CXXDefaultConstructor;
+
     if (Ctor->isCopyConstructor())
       return Sema::CXXCopyConstructor;
-    
+
     if (Ctor->isMoveConstructor())
       return Sema::CXXMoveConstructor;
-    
-    if (Ctor->isDefaultConstructor())
-      return Sema::CXXDefaultConstructor;
   } else if (isa<CXXDestructorDecl>(MD)) {
     return Sema::CXXDestructor;
   } else if (MD->isCopyAssignmentOperator()) {
index 6870f3c46b2c950001aca6850e21cafb77335cd0..2fd4cf58cad6d070f03b4bee08711c4b163fb8c3 100644 (file)
@@ -457,6 +457,15 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) {
              diag::err_param_default_argument_member_template_redecl)
           << WhichKind
           << NewParam->getDefaultArgRange();
+      } else if (CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(New)) {
+        CXXSpecialMember NewSM = getSpecialMember(Ctor),
+                         OldSM = getSpecialMember(cast<CXXConstructorDecl>(Old));
+        if (NewSM != OldSM) {
+          Diag(NewParam->getLocation(),diag::warn_default_arg_makes_ctor_special)
+            << NewParam->getDefaultArgRange() << NewSM;
+          Diag(Old->getLocation(), diag::note_previous_declaration_special)
+            << OldSM;
+        }
       }
     }
   }
index 9809bfc84bbf8c702499327756edd19c08f0f811..64a7d58e19ef799285586debffeed28671aafe3c 100644 (file)
@@ -13,10 +13,10 @@ void g() {
 namespace PR6064 {
   struct A {
     A() { }
-    inline A(A&, int);
+    inline A(A&, int); // expected-note {{was not a special member function}}
   };
 
-  A::A(A&, int = 0) { }
+  A::A(A&, int = 0) { } // expected-warning {{makes this constructor a copy constructor}}
 
   void f() {
     A const a;
diff --git a/test/SemaCXX/default-arg-special-member.cpp b/test/SemaCXX/default-arg-special-member.cpp
new file mode 100644 (file)
index 0000000..aadbbeb
--- /dev/null
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+class foo {
+  foo(foo&, int); // expected-note {{was not a special member function}}
+  foo(int); // expected-note {{was not a special member function}}
+  foo(const foo&); // expected-note {{was a copy constructor}}
+};
+
+foo::foo(foo&, int = 0) { } // expected-warning {{makes this constructor a copy constructor}}
+foo::foo(int = 0) { } // expected-warning {{makes this constructor a default constructor}}
+foo::foo(const foo& = 0) { } //expected-warning {{makes this constructor a default constructor}}