From b8abff66a8d30356c82314c4734c692cdd479e5e Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Wed, 28 Nov 2012 03:45:24 +0000 Subject: [PATCH] C++ core issue 1344, PR10618: promote "addition of default argument makes this 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 | 1 - include/clang/Basic/DiagnosticSemaKinds.td | 8 +--- lib/Sema/SemaDeclCXX.cpp | 25 +++++++----- .../CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp | 3 +- test/SemaCXX/copy-constructor-error.cpp | 40 +++++++++++++++++-- test/SemaCXX/default-arg-special-member.cpp | 12 ------ 6 files changed, 56 insertions(+), 33 deletions(-) delete mode 100644 test/SemaCXX/default-arg-special-member.cpp diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td index f9f9ec7830..cae627ed23 100644 --- a/include/clang/Basic/DiagnosticGroups.td +++ b/include/clang/Basic/DiagnosticGroups.td @@ -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">; diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index a9e24016e3..8d172ca581 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -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; -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">; diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index e950f3eb09..86da9e907b 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -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(New)) { - CXXSpecialMember NewSM = getSpecialMember(Ctor), - OldSM = getSpecialMember(cast(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(New) && + New->getMinRequiredArguments() < Old->getMinRequiredArguments()) { + CXXSpecialMember NewSM = getSpecialMember(cast(New)), + OldSM = getSpecialMember(cast(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. diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp index dfc1d3d04b..ad156c8ded 100644 --- a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp +++ b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp @@ -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; diff --git a/test/SemaCXX/copy-constructor-error.cpp b/test/SemaCXX/copy-constructor-error.cpp index 64a7d58e19..6ffed9bf22 100644 --- a/test/SemaCXX/copy-constructor-error.cpp +++ b/test/SemaCXX/copy-constructor-error.cpp @@ -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 index 8402d3829d..0000000000 --- a/test/SemaCXX/default-arg-special-member.cpp +++ /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}} -- 2.40.0