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