r241428 - PR24030, PR24033: Consistently check whether a new declaration conflicts with
Richard Smith
richard-llvm at metafoo.co.uk
Sun Jul 5 21:43:58 PDT 2015
Author: rsmith
Date: Sun Jul 5 23:43:58 2015
New Revision: 241428
URL: http://llvm.org/viewvc/llvm-project?rev=241428&view=rev
Log:
PR24030, PR24033: Consistently check whether a new declaration conflicts with
an existing using shadow declaration if they define entities of the same kind
in different namespaces.
We'd previously check this consistently if the using-declaration came after the
other declaration, but not if it came before.
Modified:
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaTemplate.cpp
cfe/trunk/test/SemaCXX/lookup-member.cpp
cfe/trunk/test/SemaCXX/using-decl-1.cpp
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=241428&r1=241427&r2=241428&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Sun Jul 5 23:43:58 2015
@@ -2577,6 +2577,48 @@ static bool haveIncompatibleLanguageLink
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(FunctionDec
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, Lo
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
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
}
}
+ // 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
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
Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=241428&r1=241427&r2=241428&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Sun Jul 5 23:43:58 2015
@@ -957,8 +957,7 @@ Sema::CheckClassTemplate(Scope *S, unsig
// 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, unsig
}
}
} 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
Modified: cfe/trunk/test/SemaCXX/lookup-member.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/lookup-member.cpp?rev=241428&r1=241427&r2=241428&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/lookup-member.cpp (original)
+++ cfe/trunk/test/SemaCXX/lookup-member.cpp Sun Jul 5 23:43:58 2015
@@ -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 {
Modified: cfe/trunk/test/SemaCXX/using-decl-1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/using-decl-1.cpp?rev=241428&r1=241427&r2=241428&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/using-decl-1.cpp (original)
+++ cfe/trunk/test/SemaCXX/using-decl-1.cpp Sun Jul 5 23:43:58 2015
@@ -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}}
+ }
+}
More information about the cfe-commits
mailing list