From ae68b55fb592110eefa87da47107aa3464f5a713 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Wed, 30 Apr 2014 18:03:21 +0000 Subject: [PATCH] When typo-correcting a member using-declaration, only consider members of base classes. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@207680 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaDeclCXX.cpp | 21 +++++++++++---------- test/SemaCXX/using-decl-1.cpp | 11 ++++------- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index d49e68e027..b1b67a648b 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -7318,9 +7318,9 @@ namespace { class UsingValidatorCCC : public CorrectionCandidateCallback { public: UsingValidatorCCC(bool HasTypenameKeyword, bool IsInstantiation, - bool RequireMember) + CXXRecordDecl *RequireMemberOf) : HasTypenameKeyword(HasTypenameKeyword), - IsInstantiation(IsInstantiation), RequireMember(RequireMember) {} + IsInstantiation(IsInstantiation), RequireMemberOf(RequireMemberOf) {} bool ValidateCandidate(const TypoCorrection &Candidate) override { NamedDecl *ND = Candidate.getCorrectionDecl(); @@ -7329,13 +7329,14 @@ public: if (!ND || isa(ND)) return false; - // FIXME: We should check if ND is member of base class of class having - // using declaration and direct base class in case using declaration names - // a constructor. - if (RequireMember && !ND->isCXXClassMember()) - return false; + if (RequireMemberOf) { + auto *RD = dyn_cast(ND->getDeclContext()); + if (!RD || RequireMemberOf->isProvablyNotDerivedFrom(RD)) + return false; + // FIXME: Check that the base class member is accessible? + } - if (RequireMember && !isa(ND) && !isa(ND) && + if (RequireMemberOf && !isa(ND) && !isa(ND) && !isa(ND)) return false; @@ -7352,7 +7353,7 @@ public: private: bool HasTypenameKeyword; bool IsInstantiation; - bool RequireMember; + CXXRecordDecl *RequireMemberOf; }; } // end anonymous namespace @@ -7476,7 +7477,7 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, // Try to correct typos if possible. if (R.empty()) { UsingValidatorCCC CCC(HasTypenameKeyword, IsInstantiation, - CurContext->isRecord()); + dyn_cast(CurContext)); if (TypoCorrection Corrected = CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), S, &SS, CCC, CTK_ErrorRecovery)){ diff --git a/test/SemaCXX/using-decl-1.cpp b/test/SemaCXX/using-decl-1.cpp index d5e793bbb5..2ce0b10908 100644 --- a/test/SemaCXX/using-decl-1.cpp +++ b/test/SemaCXX/using-decl-1.cpp @@ -207,7 +207,7 @@ struct Y : S { using S::S; // expected-error {{no member named 'S' in 'S'}} }; -// [namespace.udecl] Para3: In a using-declaration used as a member-declaration, +// [namespace.udecl]p3: In a using-declaration used as a member-declaration, // the nested-name-specifier shall name a base class of the class being defined. // If such a using-declaration names a constructor, the nested-name-specifier // shall name a direct base class of the class being defined; @@ -216,14 +216,11 @@ struct Y : S { struct PR19171_B { }; // expected-note {{'PR19171_B' declared here}} struct PR19171_C : PR19171_B { }; struct PR19171_D : PR19171_C { - using PR19171_B::PR19171_C; // expected-error{{no member named 'PR19171_C' in 'PR19171_B'; did you mean 'PR19171_B'?}} + using PR19171_B::PR19171_C; // expected-error{{no member named 'PR19171_C' in 'PR19171_B'; did you mean 'PR19171_B'?}} }; -// FIXME: Typo correction should only consider member of base classes struct PR19171_E { }; -struct PR19171_EE { int EE; }; // expected-note {{'PR19171_EE::EE' declared here}} \ - // expected-note {{target of using declaration}} +struct PR19171_EE { int EE; }; struct PR19171_F : PR19171_E { - using PR19171_E::EE; // expected-error{{no member named 'EE' in 'PR19171_E'; did you mean 'PR19171_EE::EE'?}} \ - // expected-error{{using declaration refers into 'PR19171_E::', which is not a base class of 'PR19171_F'}} + using PR19171_E::EE; // expected-error-re{{no member named 'EE' in 'PR19171_E'{{$}}}} }; -- 2.40.0