r227939 - [modules] Be sure to load the lexical definition of a class template
Richard Smith
richard-llvm at metafoo.co.uk
Mon Feb 2 19:32:15 PST 2015
Author: rsmith
Date: Mon Feb 2 21:32:14 2015
New Revision: 227939
URL: http://llvm.org/viewvc/llvm-project?rev=227939&view=rev
Log:
[modules] Be sure to load the lexical definition of a class template
specialization from an update record exactly once, even if we needed to fake up
the definition.
Added:
cfe/trunk/test/Modules/Inputs/merge-template-members/a.h
cfe/trunk/test/Modules/Inputs/merge-template-members/b.h
cfe/trunk/test/Modules/Inputs/merge-template-members/c.h
Modified:
cfe/trunk/include/clang/Serialization/ASTReader.h
cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
cfe/trunk/test/Modules/Inputs/merge-template-members/module.modulemap
cfe/trunk/test/Modules/merge-template-members.cpp
Modified: cfe/trunk/include/clang/Serialization/ASTReader.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTReader.h?rev=227939&r1=227938&r2=227939&view=diff
==============================================================================
--- cfe/trunk/include/clang/Serialization/ASTReader.h (original)
+++ cfe/trunk/include/clang/Serialization/ASTReader.h Mon Feb 2 21:32:14 2015
@@ -435,9 +435,11 @@ private:
llvm::SmallVector<std::pair<serialization::GlobalDeclID, Decl*>, 16>
PendingUpdateRecords;
+ enum class PendingFakeDefinitionKind { NotFake, Fake, FakeLoaded };
+
/// \brief The DefinitionData pointers that we faked up for class definitions
/// that we needed but hadn't loaded yet.
- llvm::SmallPtrSet<void*, 4> PendingFakeDefinitionData;
+ llvm::DenseMap<void *, PendingFakeDefinitionKind> PendingFakeDefinitionData;
struct ReplacedDeclInfo {
ModuleFile *Mod;
Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=227939&r1=227938&r2=227939&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Mon Feb 2 21:32:14 2015
@@ -103,7 +103,7 @@ namespace clang {
return Reader.getSubmodule(readSubmoduleID(R, I));
}
- void ReadCXXRecordDefinition(CXXRecordDecl *D);
+ void ReadCXXRecordDefinition(CXXRecordDecl *D, bool Update);
void ReadCXXDefinitionData(struct CXXRecordDecl::DefinitionData &Data,
const RecordData &R, unsigned &I);
void MergeDefinitionData(CXXRecordDecl *D,
@@ -1360,11 +1360,13 @@ void ASTDeclReader::MergeDefinitionData(
"merging class definition into non-definition");
auto &DD = *D->DefinitionData.getNotUpdated();
- if (Reader.PendingFakeDefinitionData.count(&DD)) {
+ auto PFDI = Reader.PendingFakeDefinitionData.find(&DD);
+ if (PFDI != Reader.PendingFakeDefinitionData.end() &&
+ PFDI->second == ASTReader::PendingFakeDefinitionKind::Fake) {
// We faked up this definition data because we found a class for which we'd
// not yet loaded the definition. Replace it with the real thing now.
- Reader.PendingFakeDefinitionData.erase(&DD);
assert(!DD.IsLambda && !MergeDD.IsLambda && "faked up lambda definition?");
+ PFDI->second = ASTReader::PendingFakeDefinitionKind::FakeLoaded;
// Don't change which declaration is the definition; that is required
// to be invariant once we select it.
@@ -1458,7 +1460,7 @@ void ASTDeclReader::MergeDefinitionData(
Reader.PendingOdrMergeFailures[DD.Definition].push_back(MergeDD.Definition);
}
-void ASTDeclReader::ReadCXXRecordDefinition(CXXRecordDecl *D) {
+void ASTDeclReader::ReadCXXRecordDefinition(CXXRecordDecl *D, bool Update) {
struct CXXRecordDecl::DefinitionData *DD;
ASTContext &C = Reader.getContext();
@@ -1491,6 +1493,11 @@ void ASTDeclReader::ReadCXXRecordDefinit
if (Canon == D) {
D->DefinitionData = DD;
D->IsCompleteDefinition = true;
+
+ // If this is an update record, we can have redeclarations already. Make a
+ // note that we need to propagate the DefinitionData pointer onto them.
+ if (Update)
+ Reader.PendingDefinitions.insert(D);
} else if (auto *CanonDD = Canon->DefinitionData.getNotUpdated()) {
// We have already deserialized a definition of this record. This
// definition is no longer really a definition. Note that the pre-existing
@@ -1556,7 +1563,7 @@ ASTDeclReader::VisitCXXRecordDeclImpl(CX
bool WasDefinition = Record[Idx++];
if (WasDefinition)
- ReadCXXRecordDefinition(D);
+ ReadCXXRecordDefinition(D, /*Update*/false);
else
// Propagate DefinitionData pointer from the canonical declaration.
D->DefinitionData = D->getCanonicalDecl()->DefinitionData;
@@ -2573,7 +2580,8 @@ DeclContext *ASTDeclReader::getPrimaryCo
RD->getCanonicalDecl()->DefinitionData = DD;
// Track that we did this horrible thing so that we can fix it later.
- Reader.PendingFakeDefinitionData.insert(DD);
+ Reader.PendingFakeDefinitionData.insert(
+ std::make_pair(DD, ASTReader::PendingFakeDefinitionKind::Fake));
}
return DD->Definition;
@@ -3638,18 +3646,19 @@ void ASTDeclReader::UpdateDecl(Decl *D,
case UPD_CXX_INSTANTIATED_CLASS_DEFINITION: {
auto *RD = cast<CXXRecordDecl>(D);
- bool HadRealDefinition = RD->getDefinition() &&
- !Reader.PendingFakeDefinitionData.count(
- RD->DefinitionData.getNotUpdated());
- ReadCXXRecordDefinition(RD);
+ auto *OldDD = RD->DefinitionData.getNotUpdated();
+ bool HadRealDefinition =
+ OldDD && !Reader.PendingFakeDefinitionData.count(OldDD);
+ ReadCXXRecordDefinition(RD, /*Update*/true);
+
// Visible update is handled separately.
uint64_t LexicalOffset = Record[Idx++];
if (!HadRealDefinition && LexicalOffset) {
RD->setHasExternalLexicalStorage(true);
Reader.ReadDeclContextStorage(ModuleFile, ModuleFile.DeclsCursor,
- std::make_pair(LexicalOffset, 0),
- ModuleFile.DeclContextInfos[RD]);
- Reader.PendingDefinitions.insert(RD);
+ std::make_pair(LexicalOffset, 0),
+ ModuleFile.DeclContextInfos[RD]);
+ Reader.PendingFakeDefinitionData.erase(OldDD);
}
auto TSK = (TemplateSpecializationKind)Record[Idx++];
Added: cfe/trunk/test/Modules/Inputs/merge-template-members/a.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/merge-template-members/a.h?rev=227939&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/merge-template-members/a.h (added)
+++ cfe/trunk/test/Modules/Inputs/merge-template-members/a.h Mon Feb 2 21:32:14 2015
@@ -0,0 +1,9 @@
+namespace N {
+ template <typename> struct A {
+ int n;
+ A() : n() {}
+ };
+
+ // Create declaration of A<int>.
+ typedef A<int> AI;
+}
Added: cfe/trunk/test/Modules/Inputs/merge-template-members/b.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/merge-template-members/b.h?rev=227939&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/merge-template-members/b.h (added)
+++ cfe/trunk/test/Modules/Inputs/merge-template-members/b.h Mon Feb 2 21:32:14 2015
@@ -0,0 +1,6 @@
+#include "a.h"
+
+// Add update record for definition of A<int> and constructors.
+// We need an eagerly-emitted function here to get the problematic
+// deserialization ordering.
+void foobar() { N::A<int> x; }
Added: cfe/trunk/test/Modules/Inputs/merge-template-members/c.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/merge-template-members/c.h?rev=227939&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/merge-template-members/c.h (added)
+++ cfe/trunk/test/Modules/Inputs/merge-template-members/c.h Mon Feb 2 21:32:14 2015
@@ -0,0 +1,14 @@
+namespace N {
+ template <typename> struct A {
+ int n;
+ A() : n() {}
+ };
+
+ // Trigger instantiation of definition of A<int>.
+ struct C {
+ A<int> a;
+ };
+}
+
+// Merge in another declaration and update records.
+#include "b.h"
Modified: cfe/trunk/test/Modules/Inputs/merge-template-members/module.modulemap
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/merge-template-members/module.modulemap?rev=227939&r1=227938&r2=227939&view=diff
==============================================================================
--- cfe/trunk/test/Modules/Inputs/merge-template-members/module.modulemap (original)
+++ cfe/trunk/test/Modules/Inputs/merge-template-members/module.modulemap Mon Feb 2 21:32:14 2015
@@ -1,2 +1,6 @@
module def { header "def.h" export * }
module update { header "update.h" export * }
+
+module a { header "a.h" export * }
+module b { header "b.h" export * }
+module c { header "c.h" export * }
Modified: cfe/trunk/test/Modules/merge-template-members.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/merge-template-members.cpp?rev=227939&r1=227938&r2=227939&view=diff
==============================================================================
--- cfe/trunk/test/Modules/merge-template-members.cpp (original)
+++ cfe/trunk/test/Modules/merge-template-members.cpp Mon Feb 2 21:32:14 2015
@@ -1,7 +1,10 @@
// RUN: rm -rf %t
-// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -I%S/Inputs/merge-template-members -verify %s
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -I%S/Inputs/merge-template-members -verify -emit-llvm-only %s
// expected-no-diagnostics
+#include "c.h"
+N::A<int> ai;
+
template<typename> struct A { int n; };
template<typename> struct B { typedef A<void> C; };
template class B<int>;
More information about the cfe-commits
mailing list