From 838925dc841f0968ac5daf941aed5d2331775a59 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Fri, 13 Jul 2012 04:12:04 +0000 Subject: [PATCH] Provide a special-case diagnostic when two class member functions instantiate to the same signature. Fix a bug in the type printer which would cause this diagnostic to print wonderful types like 'const const int *'. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@160161 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticSemaKinds.td | 2 ++ lib/AST/TypePrinter.cpp | 14 ++++++++--- lib/Sema/SemaDecl.cpp | 27 +++++++++++++--------- test/SemaTemplate/instantiate-method.cpp | 9 +++++++- 4 files changed, 37 insertions(+), 15 deletions(-) diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 769285a0b8..b08b342819 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -3799,6 +3799,8 @@ def note_enum_specialized_here : Note< "enum %0 was explicitly specialized here">; def err_member_redeclared : Error<"class member cannot be redeclared">; +def err_member_redeclared_in_instantiation : Error< + "multiple overloads of %0 instantiate to the same signature %1">; def err_member_name_of_class : Error<"member %0 has the same name as its class">; def err_member_def_undefined_record : Error< "out-of-line definition of %0 from class %1 without definition">; diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp index 7567a73311..c42117c82b 100644 --- a/lib/AST/TypePrinter.cpp +++ b/lib/AST/TypePrinter.cpp @@ -226,9 +226,17 @@ bool TypePrinter::canPrefixQualifiers(const Type *T, return CanPrefixQualifiers; } -void TypePrinter::printBefore(QualType t, raw_ostream &OS) { - SplitQualType split = t.split(); - printBefore(split.Ty, split.Quals, OS); +void TypePrinter::printBefore(QualType T, raw_ostream &OS) { + SplitQualType Split = T.split(); + + // If we have cv1 T, where T is substituted for cv2 U, only print cv1 - cv2 + // at this level. + Qualifiers Quals = Split.Quals; + if (const SubstTemplateTypeParmType *Subst = + dyn_cast(Split.Ty)) + Quals -= QualType(Subst, 0).getQualifiers(); + + printBefore(Split.Ty, Quals, OS); } /// \brief Prints the part of the type string before an identifier, e.g. for diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index f00ed8279b..cbf2368f71 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -2063,22 +2063,27 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) { 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; + if (ActiveTemplateInstantiations.empty()) { + 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(New->getLocation(), NewDiag); + } else { + Diag(New->getLocation(), diag::err_member_redeclared_in_instantiation) + << New << New->getType(); + } Diag(Old->getLocation(), PrevDiag) << Old << Old->getType(); // Complain if this is an explicit declaration of a special diff --git a/test/SemaTemplate/instantiate-method.cpp b/test/SemaTemplate/instantiate-method.cpp index 363115d184..5e9da3f688 100644 --- a/test/SemaTemplate/instantiate-method.cpp +++ b/test/SemaTemplate/instantiate-method.cpp @@ -173,5 +173,12 @@ namespace PR7022 { typedef X2<> X2_type; X2_type c; } - +} + +namespace SameSignatureAfterInstantiation { + template struct S { + void f(T *); // expected-note {{previous}} + void f(const T*); // expected-error {{multiple overloads of 'f' instantiate to the same signature 'void (const int *)'}} + }; + S s; // expected-note {{instantiation}} }