From: Alex Lorenz Date: Fri, 28 Apr 2017 12:30:05 +0000 (+0000) Subject: [Sema] Avoid an invalid redefinition error that was presented for X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ad2cd105c1db6ce184f256cfcbe15abdb480c51f;p=clang [Sema] Avoid an invalid redefinition error that was presented for of a function whose previous definition was typo-corrected rdar://28550928 Differential Revision: https://reviews.llvm.org/D25113 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@301643 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 4aa016e278..19c42a8c56 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -1068,6 +1068,12 @@ public: /// same special member, we should act as if it is not yet declared. llvm::SmallSet SpecialMembersBeingDeclared; + /// The function definitions which were renamed as part of typo-correction + /// to match their respective declarations. We want to keep track of them + /// to ensure that we don't emit a "redefinition" error if we encounter a + /// correctly named definition after the renamed definition. + llvm::SmallPtrSet TypoCorrectedFunctionDefinitions; + void ReadMethodPool(Selector Sel); void updateOutOfDateSelector(Selector Sel); @@ -3117,6 +3123,8 @@ public: const PartialDiagnostic &PrevNote, bool ErrorRecovery = true); + void MarkTypoCorrectedFunctionDefinition(const NamedDecl *F); + void FindAssociatedClassesAndNamespaces(SourceLocation InstantiationLoc, ArrayRef Args, AssociatedNamespaceSet &AssociatedNamespaces, diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index cffeb0bc7f..054ccb64cb 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -7424,6 +7424,10 @@ class DifferentNameValidatorCCC : public CorrectionCandidateCallback { } // end anonymous namespace +void Sema::MarkTypoCorrectedFunctionDefinition(const NamedDecl *F) { + TypoCorrectedFunctionDefinitions.insert(F); +} + /// \brief Generate diagnostics for an invalid function redeclaration. /// /// This routine handles generating the diagnostic messages for an invalid @@ -7521,6 +7525,8 @@ static NamedDecl *DiagnoseInvalidRedeclaration( if ((*I)->getCanonicalDecl() == Canonical) Correction.setCorrectionDecl(*I); + // Let Sema know about the correction. + SemaRef.MarkTypoCorrectedFunctionDefinition(Result); SemaRef.diagnoseTypo( Correction, SemaRef.PDiag(IsLocalFriend @@ -11732,6 +11738,11 @@ Sema::CheckForFunctionRedefinition(FunctionDecl *FD, if (canRedefineFunction(Definition, getLangOpts())) return; + // Don't emit an error when this is redifinition of a typo-corrected + // definition. + if (TypoCorrectedFunctionDefinitions.count(Definition)) + return; + // If we don't have a visible definition of the function, and it's inline or // a template, skip the new definition. if (SkipBody && !hasVisibleDefinition(Definition) && diff --git a/test/SemaCXX/typo-correction.cpp b/test/SemaCXX/typo-correction.cpp index 48597ded15..c59ee618f9 100644 --- a/test/SemaCXX/typo-correction.cpp +++ b/test/SemaCXX/typo-correction.cpp @@ -679,3 +679,30 @@ int g() { sizeof(c0is0)]; // expected-error {{use of undeclared identifier}} }; } + +namespace avoidRedundantRedefinitionErrors { +class Class { + void function(int pid); // expected-note {{'function' declared here}} +}; + +void Class::function2(int pid) { // expected-error {{out-of-line definition of 'function2' does not match any declaration in 'avoidRedundantRedefinitionErrors::Class'; did you mean 'function'?}} +} + +// Expected no redefinition error here. +void Class::function(int pid) { // expected-note {{previous definition is here}} +} + +void Class::function(int pid) { // expected-error {{redefinition of 'function'}} +} + +namespace ns { +void create_test(); // expected-note {{'create_test' declared here}} +} + +void ns::create_test2() { // expected-error {{out-of-line definition of 'create_test2' does not match any declaration in namespace 'avoidRedundantRedefinitionErrors::ns'; did you mean 'create_test'?}} +} + +// Expected no redefinition error here. +void ns::create_test() { +} +}