]> granicus.if.org Git - clang/commitdiff
Serialize the IDNS for a UsingShadowDecl rather than recomputing it.
authorRichard Smith <richard-llvm@metafoo.co.uk>
Sat, 6 Jan 2018 01:07:05 +0000 (01:07 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Sat, 6 Jan 2018 01:07:05 +0000 (01:07 +0000)
Attempting to recompute it are doomed to fail because the IDNS of a declaration
is not necessarily preserved across serialization and deserialization (in turn
because whether a friend declaration is visible depends on whether some prior
non-friend declaration exists).

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@321921 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/DeclCXX.h
lib/AST/DeclCXX.cpp
lib/Serialization/ASTReaderDecl.cpp
lib/Serialization/ASTWriterDecl.cpp
test/Modules/using-decl-friend-2.cpp [new file with mode: 0644]

index 88dc9a655917299735e841fd50e24be21de2ac6b..9f19c060f2c1db1dc3afa6f2ca370e781b87781e 100644 (file)
@@ -3129,10 +3129,14 @@ public:
 
   /// \brief Sets the underlying declaration which has been brought into the
   /// local scope.
-  void setTargetDecl(NamedDeclND) {
+  void setTargetDecl(NamedDecl *ND) {
     assert(ND && "Target decl is null!");
     Underlying = ND;
-    IdentifierNamespace = ND->getIdentifierNamespace();
+    // A UsingShadowDecl is never a friend or local extern declaration, even
+    // if it is a shadow declaration for one.
+    IdentifierNamespace =
+        ND->getIdentifierNamespace() &
+        ~(IDNS_OrdinaryFriend | IDNS_TagFriend | IDNS_LocalExtern);
   }
 
   /// \brief Gets the using declaration to which this declaration is tied.
index 41f2449a9d6a09722764c07d5c5ed8c26326af0f..afbc3f315f5d31b489b2a235b73cc978a0fbb43c 100644 (file)
@@ -2387,10 +2387,10 @@ UsingShadowDecl::UsingShadowDecl(Kind K, ASTContext &C, DeclContext *DC,
                                  SourceLocation Loc, UsingDecl *Using,
                                  NamedDecl *Target)
     : NamedDecl(K, DC, Loc, Using ? Using->getDeclName() : DeclarationName()),
-      redeclarable_base(C), Underlying(Target),
+      redeclarable_base(C), Underlying(),
       UsingOrNextShadow(cast<NamedDecl>(Using)) {
   if (Target)
-    IdentifierNamespace = Target->getIdentifierNamespace();
+    setTargetDecl(Target);
   setImplicit();
 }
 
index efbaf92a849ae370dc54a0243f6b3e8ef8dd7a3f..0cf9afb0759c9a3644dfc148b3dc60f52ca66e63 100644 (file)
@@ -1500,7 +1500,8 @@ void ASTDeclReader::VisitUsingPackDecl(UsingPackDecl *D) {
 void ASTDeclReader::VisitUsingShadowDecl(UsingShadowDecl *D) {
   RedeclarableResult Redecl = VisitRedeclarable(D);
   VisitNamedDecl(D);
-  D->setTargetDecl(ReadDeclAs<NamedDecl>());
+  D->Underlying = ReadDeclAs<NamedDecl>();
+  D->IdentifierNamespace = Record.readInt();
   D->UsingOrNextShadow = ReadDeclAs<NamedDecl>();
   UsingShadowDecl *Pattern = ReadDeclAs<UsingShadowDecl>();
   if (Pattern)
index bb72a3b383ea891580387d778bde981f848e44a5..341f0e16075cc9004c24714eebba266abbec0e6e 100644 (file)
@@ -1192,6 +1192,7 @@ void ASTDeclWriter::VisitUsingShadowDecl(UsingShadowDecl *D) {
   VisitRedeclarable(D);
   VisitNamedDecl(D);
   Record.AddDeclRef(D->getTargetDecl());
+  Record.push_back(D->getIdentifierNamespace());
   Record.AddDeclRef(D->UsingOrNextShadow);
   Record.AddDeclRef(Context.getInstantiatedFromUsingShadowDecl(D));
   Code = serialization::DECL_USING_SHADOW;
diff --git a/test/Modules/using-decl-friend-2.cpp b/test/Modules/using-decl-friend-2.cpp
new file mode 100644 (file)
index 0000000..0c71c37
--- /dev/null
@@ -0,0 +1,39 @@
+// RUN: %clang_cc1 -fmodules %s -verify
+// expected-no-diagnostics
+
+#pragma clang module build A
+module A {}
+#pragma clang module contents
+#pragma clang module begin A
+namespace N { class X; }
+#pragma clang module end
+#pragma clang module endbuild
+
+#pragma clang module build B
+module B {}
+#pragma clang module contents
+#pragma clang module begin B
+namespace N { class Friendly { friend class X; }; }
+#pragma clang module end
+#pragma clang module endbuild
+
+#pragma clang module build C
+module C {}
+#pragma clang module contents
+#pragma clang module begin C
+#pragma clang module import A
+void use_X(N::X *p);
+#pragma clang module import B
+// UsingShadowDecl names the friend declaration
+using N::X;
+#pragma clang module end
+#pragma clang module endbuild
+
+#pragma clang module import B
+namespace N { class AlsoFriendly { friend class X; }; }
+#pragma clang module import A
+#pragma clang module import C
+// The friend declaration from N::Friendly is now the first in the redecl
+// chain, so is not ordinarily visible. We need the IDNS of the UsingShadowDecl
+// to still consider it to be visible, though.
+X *p;