From f5013f013edc47d0a2a11d300536721cc1c060b6 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Thu, 18 Jun 2015 22:07:00 +0000 Subject: [PATCH] [modules] Merging support for enums with a local definition prior to the first imported definition. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@240068 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Serialization/ASTReaderDecl.cpp | 97 ++++++++++++++++------------- test/Modules/merge-enumerators.cpp | 11 ++++ 2 files changed, 65 insertions(+), 43 deletions(-) create mode 100644 test/Modules/merge-enumerators.cpp diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index 4d64c52bee..a3cbce0e3c 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -389,6 +389,48 @@ namespace clang { }; } +namespace { +/// Iterator over the redeclarations of a declaration that have already +/// been merged into the same redeclaration chain. +template +class MergedRedeclIterator { + DeclT *Start, *Canonical, *Current; +public: + MergedRedeclIterator() : Current(nullptr) {} + MergedRedeclIterator(DeclT *Start) + : Start(Start), Canonical(nullptr), Current(Start) {} + + DeclT *operator*() { return Current; } + + MergedRedeclIterator &operator++() { + if (Current->isFirstDecl()) { + Canonical = Current; + Current = Current->getMostRecentDecl(); + } else + Current = Current->getPreviousDecl(); + + // If we started in the merged portion, we'll reach our start position + // eventually. Otherwise, we'll never reach it, but the second declaration + // we reached was the canonical declaration, so stop when we see that one + // again. + if (Current == Start || Current == Canonical) + Current = nullptr; + return *this; + } + + friend bool operator!=(const MergedRedeclIterator &A, + const MergedRedeclIterator &B) { + return A.Current != B.Current; + } +}; +} +template +llvm::iterator_range> merged_redecls(DeclT *D) { + return llvm::iterator_range>( + MergedRedeclIterator(D), + MergedRedeclIterator()); +} + uint64_t ASTDeclReader::GetCurrentCursorOffset() { return F.DeclsCursor.GetCurrentBitNo() + F.GlobalBitOffset; } @@ -606,7 +648,18 @@ void ASTDeclReader::VisitEnumDecl(EnumDecl *ED) { if (ED->IsCompleteDefinition && Reader.getContext().getLangOpts().Modules && Reader.getContext().getLangOpts().CPlusPlus) { - if (EnumDecl *&OldDef = Reader.EnumDefinitions[ED->getCanonicalDecl()]) { + EnumDecl *&OldDef = Reader.EnumDefinitions[ED->getCanonicalDecl()]; + if (!OldDef) { + // This is the first time we've seen an imported definition. Look for a + // local definition before deciding that we are the first definition. + for (auto *D : merged_redecls(ED->getCanonicalDecl())) { + if (!D->isFromASTFile() && D->isCompleteDefinition()) { + OldDef = D; + break; + } + } + } + if (OldDef) { Reader.MergedDeclContexts.insert(std::make_pair(ED, OldDef)); ED->IsCompleteDefinition = false; mergeDefinitionVisibility(OldDef, ED); @@ -3624,48 +3677,6 @@ void ASTReader::loadObjCCategories(serialization::GlobalDeclID ID, ModuleMgr.visit(ObjCCategoriesVisitor::visit, &Visitor); } -namespace { -/// Iterator over the redeclarations of a declaration that have already -/// been merged into the same redeclaration chain. -template -class MergedRedeclIterator { - DeclT *Start, *Canonical, *Current; -public: - MergedRedeclIterator() : Current(nullptr) {} - MergedRedeclIterator(DeclT *Start) - : Start(Start), Canonical(nullptr), Current(Start) {} - - DeclT *operator*() { return Current; } - - MergedRedeclIterator &operator++() { - if (Current->isFirstDecl()) { - Canonical = Current; - Current = Current->getMostRecentDecl(); - } else - Current = Current->getPreviousDecl(); - - // If we started in the merged portion, we'll reach our start position - // eventually. Otherwise, we'll never reach it, but the second declaration - // we reached was the canonical declaration, so stop when we see that one - // again. - if (Current == Start || Current == Canonical) - Current = nullptr; - return *this; - } - - friend bool operator!=(const MergedRedeclIterator &A, - const MergedRedeclIterator &B) { - return A.Current != B.Current; - } -}; -} -template -llvm::iterator_range> merged_redecls(DeclT *D) { - return llvm::iterator_range>( - MergedRedeclIterator(D), - MergedRedeclIterator()); -} - template static void forAllLaterRedecls(DeclT *D, Fn F) { F(D); diff --git a/test/Modules/merge-enumerators.cpp b/test/Modules/merge-enumerators.cpp new file mode 100644 index 0000000000..34a4ec9523 --- /dev/null +++ b/test/Modules/merge-enumerators.cpp @@ -0,0 +1,11 @@ +// RUN: rm -rf %t +// RUN: mkdir %t +// RUN: echo 'namespace N { enum E { A }; }' > %t/a.h +// RUN: echo '#include "a.h"' > %t/b.h +// RUN: touch %t/x.h +// RUN: echo 'module B { module b { header "b.h" } module x { header "x.h" } }' > %t/b.modulemap +// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -x c++ -fmodule-map-file=%t/b.modulemap %s -I%t -verify +// expected-no-diagnostics +#include "a.h" +#include "x.h" +N::E e = N::A; -- 2.40.0