From 4eeaec46f7de16898a2feb440d064cd1eac1dc2f Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Sun, 18 Dec 2016 22:01:46 +0000 Subject: [PATCH] Fix name hiding and redeclaration checking for dependent local using-declarations. llvm-svn: 290072 --- clang/lib/Sema/SemaDeclCXX.cpp | 40 +++++++++++++--------- clang/lib/Sema/SemaLookup.cpp | 9 +++-- .../basic.namespace/namespace.udecl/p8-cxx0x.cpp | 39 ++++++++++----------- 3 files changed, 49 insertions(+), 39 deletions(-) diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 4742995..ac643af 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -9247,6 +9247,8 @@ bool Sema::CheckUsingDeclRedeclaration(SourceLocation UsingLoc, const CXXScopeSpec &SS, SourceLocation NameLoc, const LookupResult &Prev) { + NestedNameSpecifier *Qual = SS.getScopeRep(); + // C++03 [namespace.udecl]p8: // C++0x [namespace.udecl]p10: // A using-declaration is a declaration and can therefore be used @@ -9254,10 +9256,28 @@ bool Sema::CheckUsingDeclRedeclaration(SourceLocation UsingLoc, // allowed. // // That's in non-member contexts. - if (!CurContext->getRedeclContext()->isRecord()) + if (!CurContext->getRedeclContext()->isRecord()) { + // A dependent qualifier outside a class can only ever resolve to an + // enumeration type. Therefore it conflicts with any other non-type + // declaration in the same scope. + // FIXME: How should we check for dependent type-type conflicts at block + // scope? + if (Qual->isDependent() && !HasTypenameKeyword) { + for (auto *D : Prev) { + if (!isa(D) && !isa(D)) { + bool OldCouldBeEnumerator = + isa(D) || isa(D); + Diag(NameLoc, + OldCouldBeEnumerator ? diag::err_redefinition + : diag::err_redefinition_different_kind) + << Prev.getLookupName(); + Diag(D->getLocation(), diag::note_previous_definition); + return true; + } + } + } return false; - - NestedNameSpecifier *Qual = SS.getScopeRep(); + } for (LookupResult::iterator I = Prev.begin(), E = Prev.end(); I != E; ++I) { NamedDecl *D = *I; @@ -9275,19 +9295,7 @@ bool Sema::CheckUsingDeclRedeclaration(SourceLocation UsingLoc, = dyn_cast(D)) { DTypename = true; DQual = UD->getQualifier(); - } else if (!isa(D) && Qual->isDependent() && - !HasTypenameKeyword) { - // A dependent qualifier outside a class can only ever resolve to an - // enumeration type. Therefore it conflicts with any other non-type - // declaration in the same scope. - // FIXME: How should we check for dependent type-type conflicts at block - // scope? - Diag(NameLoc, diag::err_redefinition_different_kind) - << Prev.getLookupName(); - Diag(D->getLocation(), diag::note_previous_definition); - return true; - } - else continue; + } else continue; // using decls differ if one says 'typename' and the other doesn't. // FIXME: non-dependent using decls? diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index 1fc6d4f..38a7b8c 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -450,15 +450,18 @@ static bool canHideTag(NamedDecl *D) { // Given a set of declarations in a single declarative region [...] // exactly one declaration shall declare a class name or enumeration name // that is not a typedef name and the other declarations shall all refer to - // the same variable or enumerator, or all refer to functions and function - // templates; in this case the class name or enumeration name is hidden. + // the same variable, non-static data member, or enumerator, or all refer + // to functions and function templates; in this case the class name or + // enumeration name is hidden. // C++ [basic.scope.hiding]p2: // A class name or enumeration name can be hidden by the name of a // variable, data member, function, or enumerator declared in the same // scope. + // An UnresolvedUsingValueDecl always instantiates to one of these. D = D->getUnderlyingDecl(); return isa(D) || isa(D) || isa(D) || - isa(D) || isa(D); + isa(D) || isa(D) || + isa(D); } /// Resolves the result kind of this lookup. diff --git a/clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p8-cxx0x.cpp b/clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p8-cxx0x.cpp index 8f6638e..0ea4eeb 100644 --- a/clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p8-cxx0x.cpp +++ b/clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p8-cxx0x.cpp @@ -87,12 +87,12 @@ namespace PR21933 { extern int a(); // expected-error {{different kind of symbol}} a(); - extern int b(); - using T::b; + extern int b(); // expected-note {{previous}} + using T::b; // expected-error {{different kind of symbol}} b(); - using T::c; - using U::c; + using T::c; // expected-note {{previous}} + using U::c; // expected-error-re {{redefinition of 'c'{{$}}}} c(); } @@ -101,29 +101,28 @@ namespace PR21933 { typedef struct {} Xt; // expected-error {{different kind of symbol}} (void)Xt; - using T::Xs; // expected-note {{candidate}} - struct Xs {}; // expected-note {{candidate}} - // FIXME: This is wrong, the using declaration hides the type. - Xs xs; // expected-error {{ambiguous}} + using T::Xs; // expected-note {{hidden by}} + struct Xs {}; + (void)Xs; + Xs xs; // expected-error {{must use 'struct'}} - using T::Xe; // expected-note {{candidate}} - enum Xe {}; // expected-note {{candidate}} - // FIXME: This is wrong, the using declaration hides the type. - Xe xe; // expected-error {{ambiguous}} + using T::Xe; // expected-note {{hidden by}} + enum Xe {}; + (void)Xe; + Xe xe; // expected-error {{must use 'enum'}} typedef struct {} Yt; // expected-note {{candidate}} using T::Yt; // eypected-error {{different kind of symbol}} expected-note {{candidate}} Yt yt; // expected-error {{ambiguous}} - struct Ys {}; // expected-note {{candidate}} - using T::Ys; // expected-note {{candidate}} - // FIXME: This is wrong, the using declaration hides the type. - Ys ys; // expected-error {{ambiguous}} + struct Ys {}; + using T::Ys; // expected-note {{hidden by}} + (void)Ys; + Ys ys; // expected-error {{must use 'struct'}} - enum Ye {}; // expected-note {{candidate}} - using T::Ye; // expected-note {{candidate}} - // FIXME: This is wrong, the using declaration hides the type. - Ye ye; // expected-error {{ambiguous}} + enum Ye {}; + using T::Ye; // expected-note {{hidden by}} + Ye ye; // expected-error {{must use 'enum'}} } template void type() { -- 2.7.4