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