]> granicus.if.org Git - clang/commitdiff
C++ core issue 1344, PR10618: promote "addition of default argument makes this
authorRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 28 Nov 2012 03:45:24 +0000 (03:45 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 28 Nov 2012 03:45:24 +0000 (03:45 +0000)
a special member" diagnostic from warning to error, and fix the cases where it
produced diagnostics with incorrect wording.

We don't support this as an extension, and we ban it even in C++98 mode. This
breaks too much (for instance, the ABI-specified calling convention for a type
can change if it acquires a copy constructor through the addition of a default
argument).

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

include/clang/Basic/DiagnosticGroups.td
include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaDeclCXX.cpp
test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp
test/SemaCXX/copy-constructor-error.cpp
test/SemaCXX/default-arg-special-member.cpp [deleted file]

index f9f9ec78309ac8c20f870b1fb2faee89d3fc98a3..cae627ed2313d08e42946f83d108ac6620862186 100644 (file)
@@ -43,7 +43,6 @@ def : DiagGroup<"cast-qual">;
 def : DiagGroup<"char-align">;
 def Comment : DiagGroup<"comment">;
 def : DiagGroup<"ctor-dtor-privacy">;
-def DefaultArgSpecialMember : DiagGroup<"default-arg-special-member">;
 def GNUDesignator : DiagGroup<"gnu-designator">;
 
 def DeleteNonVirtualDtor : DiagGroup<"delete-non-virtual-dtor">;
index a9e24016e3f698a83af440703d0775a47014aa84..8d172ca58172e75290cd54d72c534e7e3a61ed52 100644 (file)
@@ -2159,13 +2159,9 @@ def err_uninitialized_member_for_assign : Error<
 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<
+def err_default_arg_makes_ctor_special : Error<
   "addition of default argument on redeclaration makes this constructor a "
-  "%select{default|copy|move}0 constructor">, InGroup<DefaultArgSpecialMember>;
-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">;
+  "%select{default|copy|move}0 constructor">;
 
 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 e950f3eb09848774a354984ca731b83455255865..86da9e907be240f9e5076a5b40936d296e4e2c8f 100644 (file)
@@ -517,19 +517,26 @@ 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;
-        }
       }
     }
   }
 
+  // DR1344: If a default argument is added outside a class definition and that
+  // default argument makes the function a special member function, the program
+  // is ill-formed. This can only happen for constructors.
+  if (isa<CXXConstructorDecl>(New) &&
+      New->getMinRequiredArguments() < Old->getMinRequiredArguments()) {
+    CXXSpecialMember NewSM = getSpecialMember(cast<CXXMethodDecl>(New)),
+                     OldSM = getSpecialMember(cast<CXXMethodDecl>(Old));
+    if (NewSM != OldSM) {
+      ParmVarDecl *NewParam = New->getParamDecl(New->getMinRequiredArguments());
+      assert(NewParam->hasDefaultArg());
+      Diag(NewParam->getLocation(), diag::err_default_arg_makes_ctor_special)
+        << NewParam->getDefaultArgRange() << NewSM;
+      Diag(Old->getLocation(), diag::note_previous_declaration);
+    }
+  }
+
   // C++11 [dcl.constexpr]p1: If any declaration of a function or function
   // template has a constexpr specifier then all its declarations shall
   // contain the constexpr specifier.
index dfc1d3d04bf9d204b40b2ba64e6a556d22866c0c..ad156c8ded92dd53730da7e7b4fef95539a8b0e0 100644 (file)
@@ -272,9 +272,8 @@ namespace CtorLookup {
   struct A {
     constexpr A(const A&) {}
     A(A&) {}
-    constexpr A(int); // expected-note {{previous}}
+    constexpr A(int = 0);
   };
-  constexpr A::A(int = 0) {} // expected-warning {{default constructor}}
 
   struct B : A {
     B() = default;
index 64a7d58e19ef799285586debffeed28671aafe3c..6ffed9bf222a0149ca1813db1155c0140c894b90 100644 (file)
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s 
+// RUN: %clang_cc1 -fsyntax-only -verify %s
 
 struct S {
    S (S);  // expected-error {{copy constructor must pass its first argument by reference}}
@@ -10,16 +10,50 @@ void g() {
   S a( f() );
 }
 
+class foo {
+  foo(foo&, int); // expected-note {{previous}}
+  foo(int); // expected-note {{previous}}
+  foo(const foo&); // expected-note {{previous}}
+};
+
+foo::foo(foo&, int = 0) { } // expected-error {{makes this constructor a copy constructor}}
+foo::foo(int = 0) { } // expected-error {{makes this constructor a default constructor}}
+foo::foo(const foo& = 0) { } //expected-error {{makes this constructor a default constructor}}
+
 namespace PR6064 {
   struct A {
     A() { }
-    inline A(A&, int); // expected-note {{was not a special member function}}
+    inline A(A&, int); // expected-note {{previous}}
   };
 
-  A::A(A&, int = 0) { } // expected-warning {{makes this constructor a copy constructor}}
+  A::A(A&, int = 0) { } // expected-error {{makes this constructor a copy constructor}}
 
   void f() {
     A const a;
     A b(a);
   }
 }
+
+namespace PR10618 {
+  struct A {
+    A(int, int, int); // expected-note {{previous}}
+  };
+  A::A(int a = 0, // expected-error {{makes this constructor a default constructor}}
+       int b = 0,
+       int c = 0) {}
+
+  struct B {
+    B(int);
+    B(const B&, int); // expected-note {{previous}}
+  };
+  B::B(const B& = B(0), // expected-error {{makes this constructor a default constructor}}
+       int = 0) {
+  }
+
+  struct C {
+    C(const C&, int); // expected-note {{previous}}
+  };
+  C::C(const C&,
+       int = 0) { // expected-error {{makes this constructor a copy constructor}}
+  }
+}
diff --git a/test/SemaCXX/default-arg-special-member.cpp b/test/SemaCXX/default-arg-special-member.cpp
deleted file mode 100644 (file)
index 8402d38..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
-// RUN: %clang_cc1 -Wno-default-arg-special-member -Werror -fsyntax-only %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}}