diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 2618eb529af79dfd1d1aa0f73ab0ad0fb8836058..acd331050cfd9c7226833c65651e0c624f953264 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -2577,6 +2577,48 @@ static bool haveIncompatibleLanguageLinkages(const T *Old, const T *New) { return false; } +template<typename T> static bool isExternC(T *D) { return D->isExternC(); } +static bool isExternC(VarTemplateDecl *) { return false; } + +/// \brief Check whether a redeclaration of an entity introduced by a +/// using-declaration is valid, given that we know it's not an overload +/// (nor a hidden tag declaration). +template<typename ExpectedDecl> +static bool checkUsingShadowRedecl(Sema &S, UsingShadowDecl *OldS, + ExpectedDecl *New) { + // C++11 [basic.scope.declarative]p4: + // Given a set of declarations in a single declarative region, each of + // which specifies the same unqualified name, + // -- they shall all refer to the same entity, or all refer to functions + // and function templates; or + // -- 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 (3.3.10). + + // C++11 [namespace.udecl]p14: + // If a function declaration in namespace scope or block scope has the + // same name and the same parameter-type-list as a function introduced + // by a using-declaration, and the declarations do not declare the same + // function, the program is ill-formed. + + auto *Old = dyn_cast<ExpectedDecl>(OldS->getTargetDecl()); + if (Old && + !Old->getDeclContext()->getRedeclContext()->Equals( + New->getDeclContext()->getRedeclContext()) && + !(isExternC(Old) && isExternC(New))) + Old = nullptr; + + if (!Old) { + S.Diag(New->getLocation(), diag::err_using_decl_conflict_reverse); + S.Diag(OldS->getTargetDecl()->getLocation(), diag::note_using_decl_target); + S.Diag(OldS->getUsingDecl()->getLocation(), diag::note_using_decl) << 0; + return true; + } + return false; +} + /// MergeFunctionDecl - We just parsed a function 'New' from /// declarator D which has the same name and scope as a previous /// declaration 'Old'. Figure out how to resolve this situation, @@ -2603,28 +2645,10 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, return true; } - // C++11 [namespace.udecl]p14: - // If a function declaration in namespace scope or block scope has the - // same name and the same parameter-type-list as a function introduced - // by a using-declaration, and the declarations do not declare the same - // function, the program is ill-formed. - // Check whether the two declarations might declare the same function. - Old = dyn_cast<FunctionDecl>(Shadow->getTargetDecl()); - if (Old && - !Old->getDeclContext()->getRedeclContext()->Equals( - New->getDeclContext()->getRedeclContext()) && - !(Old->isExternC() && New->isExternC())) - Old = nullptr; - - if (!Old) { - Diag(New->getLocation(), diag::err_using_decl_conflict_reverse); - Diag(Shadow->getTargetDecl()->getLocation(), - diag::note_using_decl_target); - Diag(Shadow->getUsingDecl()->getLocation(), diag::note_using_decl) << 0; + if (checkUsingShadowRedecl<FunctionDecl>(*this, Shadow, New)) return true; - } - OldD = Old; + OldD = Old = cast<FunctionDecl>(Shadow->getTargetDecl()); } else { Diag(New->getLocation(), diag::err_redefinition_different_kind) << New->getDeclName(); @@ -3309,8 +3333,19 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { if (NewTemplate) { OldTemplate = dyn_cast<VarTemplateDecl>(Previous.getFoundDecl()); Old = OldTemplate ? OldTemplate->getTemplatedDecl() : nullptr; - } else + + if (auto *Shadow = + dyn_cast<UsingShadowDecl>(Previous.getRepresentativeDecl())) + if (checkUsingShadowRedecl<VarTemplateDecl>(*this, Shadow, NewTemplate)) + return New->setInvalidDecl(); + } else { Old = dyn_cast<VarDecl>(Previous.getFoundDecl()); + + if (auto *Shadow = + dyn_cast<UsingShadowDecl>(Previous.getRepresentativeDecl())) + if (checkUsingShadowRedecl<VarDecl>(*this, Shadow, New)) + return New->setInvalidDecl(); + } } if (!Old) { Diag(New->getLocation(), diag::err_redefinition_different_kind) @@ -11733,8 +11768,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, if (!Previous.empty()) { NamedDecl *PrevDecl = Previous.getFoundDecl(); - NamedDecl *DirectPrevDecl = - getLangOpts().MSVCCompat ? *Previous.begin() : PrevDecl; + NamedDecl *DirectPrevDecl = Previous.getRepresentativeDecl(); // It's okay to have a tag decl in the same scope as a typedef // which hides a tag decl in the same scope. Finding this @@ -11761,6 +11795,32 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, } } + // If this is a redeclaration of a using shadow declaration, it must + // declare a tag in the same context. In MSVC mode, we allow a + // redefinition if either context is within the other. + if (auto *Shadow = dyn_cast<UsingShadowDecl>(DirectPrevDecl)) { + auto *OldTag = dyn_cast<TagDecl>(PrevDecl); + if (SS.isEmpty() && TUK != TUK_Reference && TUK != TUK_Friend && + isDeclInScope(Shadow, SearchDC, S, isExplicitSpecialization) && + !(OldTag && + (getLangOpts().MSVCCompat + ? SearchDC->getRedeclContext()->Encloses( + OldTag->getDeclContext()->getRedeclContext()) || + OldTag->getDeclContext()->getRedeclContext()->Encloses( + SearchDC->getRedeclContext()) + : SearchDC->getRedeclContext()->Equals( + OldTag->getDeclContext()->getRedeclContext())))) { + Diag(KWLoc, diag::err_using_decl_conflict_reverse); + Diag(Shadow->getTargetDecl()->getLocation(), + diag::note_using_decl_target); + Diag(Shadow->getUsingDecl()->getLocation(), diag::note_using_decl) + << 0; + // Recover by ignoring the old declaration. + Previous.clear(); + goto CreateNewDecl; + } + } + if (TagDecl *PrevTagDecl = dyn_cast<TagDecl>(PrevDecl)) { // If this is a use of a previous tag, or if the tag is already declared // in the same scope (so that the definition/declaration completes or @@ -11949,7 +12009,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, Invalid = true; // Otherwise, only diagnose if the declaration is in scope. - } else if (!isDeclInScope(PrevDecl, SearchDC, S, + } else if (!isDeclInScope(DirectPrevDecl, SearchDC, S, SS.isNotEmpty() || isExplicitSpecialization)) { // do nothing diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 79df1f210e668aeca53ea33c69cf72e8c78c2ad7..97904ce599385280855a434c9d5371d0de3c060a 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -957,8 +957,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, // Check that the chosen semantic context doesn't already contain a // declaration of this name as a non-tag type. - LookupResult Previous(*this, Name, NameLoc, LookupOrdinaryName, - ForRedeclaration); + Previous.clear(LookupOrdinaryName); DeclContext *LookupContext = SemanticContext; while (LookupContext->isTransparentContext()) LookupContext = LookupContext->getLookupParent(); @@ -972,9 +971,25 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, } } } else if (PrevDecl && - !isDeclInScope(PrevDecl, SemanticContext, S, SS.isValid())) + !isDeclInScope(Previous.getRepresentativeDecl(), SemanticContext, + S, SS.isValid())) PrevDecl = PrevClassTemplate = nullptr; + if (auto *Shadow = dyn_cast_or_null<UsingShadowDecl>( + PrevDecl ? Previous.getRepresentativeDecl() : nullptr)) { + if (SS.isEmpty() && + !(PrevClassTemplate && + PrevClassTemplate->getDeclContext()->getRedeclContext()->Equals( + SemanticContext->getRedeclContext()))) { + Diag(KWLoc, diag::err_using_decl_conflict_reverse); + Diag(Shadow->getTargetDecl()->getLocation(), + diag::note_using_decl_target); + Diag(Shadow->getUsingDecl()->getLocation(), diag::note_using_decl) << 0; + // Recover by ignoring the old declaration. + PrevDecl = PrevClassTemplate = nullptr; + } + } + if (PrevClassTemplate) { // Ensure that the template parameter lists are compatible. Skip this check // for a friend in a dependent context: the template parameter list itself diff --git a/test/SemaCXX/lookup-member.cpp b/test/SemaCXX/lookup-member.cpp index 39f5a15d0811a24f787799b06af99b113c6bc48e..a2256a89d11cf335bae1e5af18d7a5a4aca187f4 100644 --- a/test/SemaCXX/lookup-member.cpp +++ b/test/SemaCXX/lookup-member.cpp @@ -1,12 +1,11 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s -// expected-no-diagnostics namespace A { - class String; + class String; // expected-note {{target of using declaration}} }; -using A::String; -class String; +using A::String; // expected-note {{using declaration}} +class String; // expected-error {{conflicts with target of using declaration}} // rdar://8603569 union value { diff --git a/test/SemaCXX/using-decl-1.cpp b/test/SemaCXX/using-decl-1.cpp index e730c9d63a209cf27f73ef19fce4eea7773ea425..ca532692c1cb0ee6d053d7013ae1fa6a8cc5a5d2 100644 --- a/test/SemaCXX/using-decl-1.cpp +++ b/test/SemaCXX/using-decl-1.cpp @@ -263,3 +263,67 @@ struct B : A { static int f() { return n; } // expected-error {{invalid use of member 'n' in static member function}} }; } + +namespace PR24030 { + namespace X { + class A; // expected-note {{target}} + int i; // expected-note {{target}} + } + namespace Y { + using X::A; // expected-note {{using}} + using X::i; // expected-note {{using}} + class A {}; // expected-error {{conflicts}} + int i; // expected-error {{conflicts}} + } +} + +namespace PR24033 { + extern int a; // expected-note 2{{target of using declaration}} + void f(); // expected-note 2{{target of using declaration}} + struct s; // expected-note 2{{target of using declaration}} + enum e {}; // expected-note 2{{target of using declaration}} + + template<typename> extern int vt; // expected-note 2{{target of using declaration}} expected-warning 0-1{{extension}} + template<typename> void ft(); // expected-note 2{{target of using declaration}} + template<typename> struct st; // expected-note 2{{target of using declaration}} + + namespace X { + using PR24033::a; // expected-note {{using declaration}} + using PR24033::f; // expected-note {{using declaration}} + using PR24033::s; // expected-note {{using declaration}} + using PR24033::e; // expected-note {{using declaration}} + + using PR24033::vt; // expected-note {{using declaration}} + using PR24033::ft; // expected-note {{using declaration}} + using PR24033::st; // expected-note {{using declaration}} + + extern int a; // expected-error {{declaration conflicts with target of using declaration already in scope}} + void f(); // expected-error {{declaration conflicts with target of using declaration already in scope}} + struct s; // expected-error {{declaration conflicts with target of using declaration already in scope}} + enum e {}; // expected-error {{declaration conflicts with target of using declaration already in scope}} + + template<typename> extern int vt; // expected-error {{declaration conflicts with target of using declaration already in scope}} expected-warning 0-1{{extension}} + template<typename> void ft(); // expected-error {{declaration conflicts with target of using declaration already in scope}} + template<typename> struct st; // expected-error {{declaration conflicts with target of using declaration already in scope}} + } + + namespace Y { + extern int a; // expected-note {{conflicting declaration}} + void f(); // expected-note {{conflicting declaration}} + struct s; // expected-note {{conflicting declaration}} + enum e {}; // expected-note {{conflicting declaration}} + + template<typename> extern int vt; // expected-note {{conflicting declaration}} expected-warning 0-1{{extension}} + template<typename> void ft(); // expected-note {{conflicting declaration}} + template<typename> struct st; // expected-note {{conflicting declaration}} + + using PR24033::a; // expected-error {{target of using declaration conflicts with declaration already in scope}} + using PR24033::f; // expected-error {{target of using declaration conflicts with declaration already in scope}} + using PR24033::s; // expected-error {{target of using declaration conflicts with declaration already in scope}} + using PR24033::e; // expected-error {{target of using declaration conflicts with declaration already in scope}} + + using PR24033::vt; // expected-error {{target of using declaration conflicts with declaration already in scope}} + using PR24033::ft; // expected-error {{target of using declaration conflicts with declaration already in scope}} + using PR24033::st; // expected-error {{target of using declaration conflicts with declaration already in scope}} + } +}