r219657 - [modules] Merging for class-scope using-declarations.

Richard Smith richard-llvm at metafoo.co.uk
Mon Oct 13 19:00:47 PDT 2014


Author: rsmith
Date: Mon Oct 13 21:00:47 2014
New Revision: 219657

URL: http://llvm.org/viewvc/llvm-project?rev=219657&view=rev
Log:
[modules] Merging for class-scope using-declarations.

Added:
    cfe/trunk/test/Modules/Inputs/merge-using-decls/
    cfe/trunk/test/Modules/Inputs/merge-using-decls/a.h
    cfe/trunk/test/Modules/Inputs/merge-using-decls/b.h
    cfe/trunk/test/Modules/Inputs/merge-using-decls/module.modulemap
    cfe/trunk/test/Modules/merge-using-decls.cpp
Modified:
    cfe/trunk/include/clang/AST/DeclCXX.h
    cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
    cfe/trunk/lib/Serialization/ASTReaderDecl.cpp

Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=219657&r1=219656&r2=219657&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Mon Oct 13 21:00:47 2014
@@ -2851,7 +2851,7 @@ public:
 /// \code
 ///    using someNameSpace::someIdentifier;
 /// \endcode
-class UsingDecl : public NamedDecl {
+class UsingDecl : public NamedDecl, public Mergeable<UsingDecl> {
   void anchor() override;
 
   /// \brief The source location of the 'using' keyword itself.
@@ -2975,6 +2975,10 @@ public:
 
   SourceRange getSourceRange() const override LLVM_READONLY;
 
+  /// Retrieves the canonical declaration of this declaration.
+  UsingDecl *getCanonicalDecl() override { return getFirstDecl(); }
+  const UsingDecl *getCanonicalDecl() const { return getFirstDecl(); }
+
   static bool classof(const Decl *D) { return classofKind(D->getKind()); }
   static bool classofKind(Kind K) { return K == Using; }
 
@@ -2993,7 +2997,8 @@ public:
 ///   using Base<T>::foo;
 /// };
 /// \endcode
-class UnresolvedUsingValueDecl : public ValueDecl {
+class UnresolvedUsingValueDecl : public ValueDecl,
+                                 public Mergeable<UnresolvedUsingValueDecl> {
   void anchor() override;
 
   /// \brief The source location of the 'using' keyword
@@ -3049,6 +3054,14 @@ public:
 
   SourceRange getSourceRange() const override LLVM_READONLY;
 
+  /// Retrieves the canonical declaration of this declaration.
+  UnresolvedUsingValueDecl *getCanonicalDecl() override {
+    return getFirstDecl();
+  }
+  const UnresolvedUsingValueDecl *getCanonicalDecl() const {
+    return getFirstDecl();
+  }
+
   static bool classof(const Decl *D) { return classofKind(D->getKind()); }
   static bool classofKind(Kind K) { return K == UnresolvedUsingValue; }
 
@@ -3067,7 +3080,9 @@ public:
 ///
 /// The type associated with an unresolved using typename decl is
 /// currently always a typename type.
-class UnresolvedUsingTypenameDecl : public TypeDecl {
+class UnresolvedUsingTypenameDecl
+    : public TypeDecl,
+      public Mergeable<UnresolvedUsingTypenameDecl> {
   void anchor() override;
 
   /// \brief The source location of the 'typename' keyword
@@ -3111,6 +3126,14 @@ public:
   static UnresolvedUsingTypenameDecl *
   CreateDeserialized(ASTContext &C, unsigned ID);
 
+  /// Retrieves the canonical declaration of this declaration.
+  UnresolvedUsingTypenameDecl *getCanonicalDecl() override {
+    return getFirstDecl();
+  }
+  const UnresolvedUsingTypenameDecl *getCanonicalDecl() const {
+    return getFirstDecl();
+  }
+
   static bool classof(const Decl *D) { return classofKind(D->getKind()); }
   static bool classofKind(Kind K) { return K == UnresolvedUsingTypename; }
 };

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=219657&r1=219656&r2=219657&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Mon Oct 13 21:00:47 2014
@@ -4293,25 +4293,26 @@ static bool isInstantiationOf(EnumDecl *
 static bool isInstantiationOf(UsingShadowDecl *Pattern,
                               UsingShadowDecl *Instance,
                               ASTContext &C) {
-  return C.getInstantiatedFromUsingShadowDecl(Instance) == Pattern;
+  return declaresSameEntity(C.getInstantiatedFromUsingShadowDecl(Instance),
+                            Pattern);
 }
 
 static bool isInstantiationOf(UsingDecl *Pattern,
                               UsingDecl *Instance,
                               ASTContext &C) {
-  return C.getInstantiatedFromUsingDecl(Instance) == Pattern;
+  return declaresSameEntity(C.getInstantiatedFromUsingDecl(Instance), Pattern);
 }
 
 static bool isInstantiationOf(UnresolvedUsingValueDecl *Pattern,
                               UsingDecl *Instance,
                               ASTContext &C) {
-  return C.getInstantiatedFromUsingDecl(Instance) == Pattern;
+  return declaresSameEntity(C.getInstantiatedFromUsingDecl(Instance), Pattern);
 }
 
 static bool isInstantiationOf(UnresolvedUsingTypenameDecl *Pattern,
                               UsingDecl *Instance,
                               ASTContext &C) {
-  return C.getInstantiatedFromUsingDecl(Instance) == Pattern;
+  return declaresSameEntity(C.getInstantiatedFromUsingDecl(Instance), Pattern);
 }
 
 static bool isInstantiationOfStaticDataMember(VarDecl *Pattern,
@@ -4377,8 +4378,8 @@ static bool isInstantiationOf(ASTContext
   if (FieldDecl *Field = dyn_cast<FieldDecl>(Other)) {
     if (!Field->getDeclName()) {
       // This is an unnamed field.
-      return Ctx.getInstantiatedFromUnnamedFieldDecl(Field) ==
-        cast<FieldDecl>(D);
+      return declaresSameEntity(Ctx.getInstantiatedFromUnnamedFieldDecl(Field),
+                                cast<FieldDecl>(D));
     }
   }
 

Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=219657&r1=219656&r2=219657&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Mon Oct 13 21:00:47 2014
@@ -1224,6 +1224,7 @@ void ASTDeclReader::VisitUsingDecl(Using
   D->setTypename(Record[Idx++]);
   if (NamedDecl *Pattern = ReadDeclAs<NamedDecl>(Record, Idx))
     Reader.getContext().setInstantiatedFromUsingDecl(D, Pattern);
+  mergeMergeable(D);
 }
 
 void ASTDeclReader::VisitUsingShadowDecl(UsingShadowDecl *D) {
@@ -1251,6 +1252,7 @@ void ASTDeclReader::VisitUnresolvedUsing
   D->setUsingLoc(ReadSourceLocation(Record, Idx));
   D->QualifierLoc = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx);
   ReadDeclarationNameLoc(D->DNLoc, D->getDeclName(), Record, Idx);
+  mergeMergeable(D);
 }
 
 void ASTDeclReader::VisitUnresolvedUsingTypenameDecl(
@@ -1258,6 +1260,7 @@ void ASTDeclReader::VisitUnresolvedUsing
   VisitTypeDecl(D);
   D->TypenameLocation = ReadSourceLocation(Record, Idx);
   D->QualifierLoc = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx);
+  mergeMergeable(D);
 }
 
 void ASTDeclReader::ReadCXXDefinitionData(
@@ -2341,6 +2344,53 @@ static bool isSameTemplateParameter(cons
                                      TY->getTemplateParameters());
 }
 
+static NamespaceDecl *getNamespace(const NestedNameSpecifier *X) {
+  if (auto *NS = X->getAsNamespace())
+    return NS;
+  if (auto *NAS = X->getAsNamespaceAlias())
+    return NAS->getNamespace();
+  return nullptr;
+}
+
+static bool isSameQualifier(const NestedNameSpecifier *X,
+                            const NestedNameSpecifier *Y) {
+  if (auto *NSX = getNamespace(X)) {
+    auto *NSY = getNamespace(Y);
+    if (!NSY || NSX->getCanonicalDecl() != NSY->getCanonicalDecl())
+      return false;
+  } else if (X->getKind() != Y->getKind())
+    return false;
+
+  // FIXME: For namespaces and types, we're permitted to check that the entity
+  // is named via the same tokens. We should probably do so.
+  switch (X->getKind()) {
+  case NestedNameSpecifier::Identifier:
+    if (X->getAsIdentifier() != Y->getAsIdentifier())
+      return false;
+    break;
+  case NestedNameSpecifier::Namespace:
+  case NestedNameSpecifier::NamespaceAlias:
+    // We've already checked that we named the same namespace.
+    break;
+  case NestedNameSpecifier::TypeSpec:
+  case NestedNameSpecifier::TypeSpecWithTemplate:
+    if (X->getAsType()->getCanonicalTypeInternal() !=
+        Y->getAsType()->getCanonicalTypeInternal())
+      return false;
+    break;
+  case NestedNameSpecifier::Global:
+  case NestedNameSpecifier::Super:
+    return true;
+  }
+
+  // Recurse into earlier portion of NNS, if any.
+  auto *PX = X->getPrefix();
+  auto *PY = Y->getPrefix();
+  if (PX && PY)
+    return isSameQualifier(PX, PY);
+  return !PX && !PY;
+}
+
 /// \brief Determine whether two template parameter lists are similar enough
 /// that they may be used in declarations of the same template.
 static bool isSameTemplateParameterList(const TemplateParameterList *X,
@@ -2448,6 +2498,24 @@ static bool isSameEntity(NamedDecl *X, N
     return USX->getTargetDecl() == USY->getTargetDecl();
   }
 
+  // Using declarations with the same qualifier match. (We already know that
+  // the name matches.)
+  if (auto *UX = dyn_cast<UsingDecl>(X)) {
+    auto *UY = cast<UsingDecl>(Y);
+    return isSameQualifier(UX->getQualifier(), UY->getQualifier()) &&
+           UX->hasTypename() == UY->hasTypename() &&
+           UX->isAccessDeclaration() == UY->isAccessDeclaration();
+  }
+  if (auto *UX = dyn_cast<UnresolvedUsingValueDecl>(X)) {
+    auto *UY = cast<UnresolvedUsingValueDecl>(Y);
+    return isSameQualifier(UX->getQualifier(), UY->getQualifier()) &&
+           UX->isAccessDeclaration() == UY->isAccessDeclaration();
+  }
+  if (auto *UX = dyn_cast<UnresolvedUsingTypenameDecl>(X))
+    return isSameQualifier(
+        UX->getQualifier(),
+        cast<UnresolvedUsingTypenameDecl>(Y)->getQualifier());
+
   // Namespace alias definitions with the same target match.
   if (auto *NAX = dyn_cast<NamespaceAliasDecl>(X)) {
     auto *NAY = cast<NamespaceAliasDecl>(Y);

Added: cfe/trunk/test/Modules/Inputs/merge-using-decls/a.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/merge-using-decls/a.h?rev=219657&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/merge-using-decls/a.h (added)
+++ cfe/trunk/test/Modules/Inputs/merge-using-decls/a.h Mon Oct 13 21:00:47 2014
@@ -0,0 +1,43 @@
+struct X {
+  int v;
+  typedef int t;
+};
+
+struct YA {
+  int value;
+  typedef int type;
+};
+
+template<typename T> struct C : X, T {
+  using T::value;
+  using typename T::type;
+  using X::v;
+  using typename X::t;
+};
+
+template<typename T> struct D : X, T {
+  using T::value;
+  using typename T::type;
+  using X::v;
+  using typename X::t;
+};
+
+template<typename T> struct E : X, T {
+  using T::value;
+  using typename T::type;
+  using X::v;
+  using typename X::t;
+};
+
+template<typename T> struct F : X, T {
+  using T::value;
+  using typename T::type;
+  using X::v;
+  using typename X::t;
+};
+
+// Force instantiation.
+typedef C<YA>::type I;
+typedef D<YA>::type I;
+typedef E<YA>::type I;
+typedef F<YA>::type I;

Added: cfe/trunk/test/Modules/Inputs/merge-using-decls/b.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/merge-using-decls/b.h?rev=219657&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/merge-using-decls/b.h (added)
+++ cfe/trunk/test/Modules/Inputs/merge-using-decls/b.h Mon Oct 13 21:00:47 2014
@@ -0,0 +1,50 @@
+struct X {
+  int v;
+  typedef int t;
+};
+
+struct YB {
+  typedef YB Y;
+  int value;
+  typedef int type;
+};
+
+struct YBRev {
+  typedef int value;
+  int type;
+};
+
+template<typename T> struct C : X, T {
+  using T::value;
+  using typename T::type;
+  using X::v;
+  using typename X::t;
+};
+
+template<typename T> struct D : X, T {
+  // Mismatch in type/non-type-ness.
+  using typename T::value;
+  using T::type;
+  using X::v;
+  using typename X::t;
+};
+
+template<typename T> struct E : X, T {
+  // Mismatch in using/access-declaration-ness.
+  T::value;
+  X::v;
+};
+
+template<typename T> struct F : X, T {
+  // Mismatch in nested-name-specifier.
+  using T::Y::value;
+  using typename T::Y::type;
+  using ::X::v;
+  using typename ::X::t;
+};
+
+// Force instantiation.
+typedef C<YB>::type I;
+typedef D<YBRev>::t I;
+typedef E<YB>::type I;
+typedef F<YB>::type I;

Added: cfe/trunk/test/Modules/Inputs/merge-using-decls/module.modulemap
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/merge-using-decls/module.modulemap?rev=219657&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/merge-using-decls/module.modulemap (added)
+++ cfe/trunk/test/Modules/Inputs/merge-using-decls/module.modulemap Mon Oct 13 21:00:47 2014
@@ -0,0 +1,2 @@
+module A { header "a.h" }
+module B { header "b.h" }

Added: cfe/trunk/test/Modules/merge-using-decls.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/merge-using-decls.cpp?rev=219657&view=auto
==============================================================================
--- cfe/trunk/test/Modules/merge-using-decls.cpp (added)
+++ cfe/trunk/test/Modules/merge-using-decls.cpp Mon Oct 13 21:00:47 2014
@@ -0,0 +1,69 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -x c++ -I%S/Inputs/merge-using-decls -verify %s -DORDER=1
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -x c++ -I%S/Inputs/merge-using-decls -verify %s -DORDER=2
+
+#if ORDER == 1
+#include "a.h"
+#include "b.h"
+#else
+#include "b.h"
+#include "a.h"
+#endif
+
+struct Y {
+  int value; // expected-note 0-1{{target of using}}
+  typedef int type; // expected-note 0-1{{target of using}}
+};
+
+template<typename T> int Use() {
+  int k = T().v + T().value; // expected-note 0-2{{instantiation of}}
+  typedef typename T::type I;
+  typedef typename T::t I;
+  typedef int I;
+  return k;
+}
+
+template<typename T> int UseAll() {
+  return Use<C<T> >() + Use<D<T> >() + Use<E<T> >() + Use<F<T> >(); // expected-note 0-2{{instantiation of}}
+}
+
+template int UseAll<YA>();
+template int UseAll<YB>();
+template int UseAll<Y>();
+
+#if ORDER == 1
+// Here, we're instantiating the definition from 'A' and merging the definition
+// from 'B' into it.
+
+// expected-error at b.h:* {{'E::value' from module 'B' is not present in definition of 'E<T>' in module 'A'}}
+// expected-error at b.h:* {{'E::v' from module 'B' is not present in definition of 'E<T>' in module 'A'}}
+
+// expected-error at b.h:* {{'F::type' from module 'B' is not present in definition of 'F<T>' in module 'A'}}
+// expected-error at b.h:* {{'F::t' from module 'B' is not present in definition of 'F<T>' in module 'A'}}
+// expected-error at b.h:* {{'F::value' from module 'B' is not present in definition of 'F<T>' in module 'A'}}
+// expected-error at b.h:* {{'F::v' from module 'B' is not present in definition of 'F<T>' in module 'A'}}
+
+// expected-note at a.h:* +{{does not match}}
+#else
+// Here, we're instantiating the definition from 'B' and merging the definition
+// from 'A' into it.
+
+// expected-error at a.h:* {{'D::type' from module 'A' is not present in definition of 'D<T>' in module 'B'}}
+// expected-error at a.h:* {{'D::value' from module 'A' is not present in definition of 'D<T>' in module 'B'}}
+// expected-error at b.h:* 2{{'typename' keyword used on a non-type}}
+// expected-error at b.h:* 2{{dependent using declaration resolved to type without 'typename'}}
+
+// expected-error at a.h:* {{'E::type' from module 'A' is not present in definition of 'E<T>' in module 'B'}}
+// expected-error at a.h:* {{'E::t' from module 'A' is not present in definition of 'E<T>' in module 'B'}}
+// expected-error at a.h:* {{'E::value' from module 'A' is not present in definition of 'E<T>' in module 'B'}}
+// expected-error at a.h:* {{'E::v' from module 'A' is not present in definition of 'E<T>' in module 'B'}}
+// expected-note at b.h:* 2{{definition has no member}}
+
+// expected-error at a.h:* {{'F::type' from module 'A' is not present in definition of 'F<T>' in module 'B'}}
+// expected-error at a.h:* {{'F::t' from module 'A' is not present in definition of 'F<T>' in module 'B'}}
+// expected-error at a.h:* {{'F::value' from module 'A' is not present in definition of 'F<T>' in module 'B'}}
+// expected-error at a.h:* {{'F::v' from module 'A' is not present in definition of 'F<T>' in module 'B'}}
+
+// expected-note at b.h:* +{{does not match}}
+// expected-note at b.h:* +{{target of using}}
+#endif





More information about the cfe-commits mailing list