diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h index a773e416670ad96bd544c94170db4593ec81c215..0aa649a84d17f5188ab56cd550eaf0e15edcd519 100644 --- a/include/clang/Serialization/ASTReader.h +++ b/include/clang/Serialization/ASTReader.h @@ -1106,6 +1106,8 @@ private: void finishPendingActions(); + void pushExternalDeclIntoScope(NamedDecl *D, DeclarationName Name); + void addPendingDeclContextInfo(Decl *D, serialization::GlobalDeclID SemaDC, serialization::GlobalDeclID LexicalDC) { diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index c06153a61a97474110ec16bc8f9b64eeb1537a2a..20d0404e4e8bd3d6a5f4412a568592bb99424061 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -6005,8 +6005,8 @@ void ASTReader::InitializeSema(Sema &S) { // Makes sure any declarations that were deserialized "too early" // still get added to the identifier's declaration chains. for (unsigned I = 0, N = PreloadedDecls.size(); I != N; ++I) { - NamedDecl *ND = cast<NamedDecl>(PreloadedDecls[I]->getMostRecentDecl()); - SemaObj->pushExternalDeclIntoScope(ND, PreloadedDecls[I]->getDeclName()); + pushExternalDeclIntoScope(PreloadedDecls[I], + PreloadedDecls[I]->getDeclName()); } PreloadedDecls.clear(); @@ -6420,8 +6420,7 @@ ASTReader::SetGloballyVisibleDecls(IdentifierInfo *II, // Introduce this declaration into the translation-unit scope // and add it to the declaration chain for this identifier, so // that (unqualified) name lookup will find it. - NamedDecl *ND = cast<NamedDecl>(D->getMostRecentDecl()); - SemaObj->pushExternalDeclIntoScope(ND, II); + pushExternalDeclIntoScope(D, II); } else { // Queue this declaration so that it will be added to the // translation unit scope and identifier's declaration chain @@ -7208,8 +7207,7 @@ void ASTReader::finishPendingActions() { TLD != TLDEnd; ++TLD) { IdentifierInfo *II = TLD->first; for (unsigned I = 0, N = TLD->second.size(); I != N; ++I) { - NamedDecl *ND = cast<NamedDecl>(TLD->second[I]->getMostRecentDecl()); - SemaObj->pushExternalDeclIntoScope(ND, II); + pushExternalDeclIntoScope(cast<NamedDecl>(TLD->second[I]), II); } } @@ -7349,6 +7347,21 @@ void ASTReader::FinishedDeserializing() { } } +void ASTReader::pushExternalDeclIntoScope(NamedDecl *D, DeclarationName Name) { + D = cast<NamedDecl>(D->getMostRecentDecl()); + + if (SemaObj->IdResolver.tryAddTopLevelDecl(D, Name) && SemaObj->TUScope) { + SemaObj->TUScope->AddDecl(D); + } else if (SemaObj->TUScope) { + // Adding the decl to IdResolver may have failed because it was already in + // (even though it was not added in scope). If it is already in, make sure + // it gets in the scope as well. + if (std::find(SemaObj->IdResolver.begin(Name), + SemaObj->IdResolver.end(), D) != SemaObj->IdResolver.end()) + SemaObj->TUScope->AddDecl(D); + } +} + ASTReader::ASTReader(Preprocessor &PP, ASTContext &Context, StringRef isysroot, bool DisableValidation, bool AllowASTWithCompilerErrors, bool UseGlobalIndex) diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index c5a055072d904f1fc56b6e5107d6d9c60e4fedb7..ba53bdaffb189a4c5ad08162b175451c09829f4a 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -3106,7 +3106,28 @@ public: for (SmallVector<Decl *, 16>::reverse_iterator D = Decls.rbegin(), DEnd = Decls.rend(); D != DEnd; ++D) - clang::io::Emit32(Out, Writer.getDeclID(*D)); + clang::io::Emit32(Out, Writer.getDeclID(getMostRecentLocalDecl(*D))); + } + + /// \brief Returns the most recent local decl or the given decl if there are + /// no local ones. The given decl is assumed to be the most recent one. + Decl *getMostRecentLocalDecl(Decl *Orig) { + // The only way a "from AST file" decl would be more recent from a local one + // is if it came from a module. + if (!PP.getLangOpts().Modules) + return Orig; + + // Look for a local in the decl chain. + for (Decl *D = Orig; D; D = D->getPreviousDecl()) { + if (!D->isFromASTFile()) + return D; + // If we come up a decl from a (chained-)PCH stop since we won't find a + // local one. + if (D->getOwningModuleID() == 0) + break; + } + + return Orig; } }; } // end anonymous namespace diff --git a/test/Modules/redecls/a.h b/test/Modules/redecls/a.h new file mode 100644 index 0000000000000000000000000000000000000000..1647f86606a80edbd10451b5dae88fc270716bb8 --- /dev/null +++ b/test/Modules/redecls/a.h @@ -0,0 +1,3 @@ +@interface AA +@end +@class AA; diff --git a/test/Modules/redecls/b.h b/test/Modules/redecls/b.h new file mode 100644 index 0000000000000000000000000000000000000000..d41573ddc78a41e58e69096b84fc2861733e4cfc --- /dev/null +++ b/test/Modules/redecls/b.h @@ -0,0 +1 @@ +@class AA; diff --git a/test/Modules/redecls/main.m b/test/Modules/redecls/main.m new file mode 100644 index 0000000000000000000000000000000000000000..9ec02b03f2cce9579412fd73cf759bedaa80717a --- /dev/null +++ b/test/Modules/redecls/main.m @@ -0,0 +1,27 @@ +// RUN: rm -rf %t.mcp +// RUN: %clang_cc1 -fmodules -x objective-c -emit-module -fmodule-name=a %S/module.map -fmodules-cache-path=%t.mcp +// RUN: %clang_cc1 -fmodules -x objective-c -emit-module -fmodule-name=b %S/module.map -fmodules-cache-path=%t.mcp +// RUN: %clang_cc1 -fmodules %s -emit-pch -o %t1.pch -fmodules-cache-path=%t.mcp +// RUN: %clang_cc1 -fmodules %s -emit-pch -o %t2.pch -include-pch %t1.pch -fmodules-cache-path=%t.mcp +// RUN: %clang_cc1 -fmodules %s -fsyntax-only -include-pch %t2.pch -fmodules-cache-path=%t.mcp -verify + +#ifndef HEADER1 +#define HEADER1 + +@import a; + +#elif !defined(HEADER2) +#define HEADER2 + +@class AA; +@import b; + +#else + +// rdar://13712705 +@interface SS : AA +@end + +#warning parsed this +#endif +// expected-warning@-2{{parsed this}} diff --git a/test/Modules/redecls/module.map b/test/Modules/redecls/module.map new file mode 100644 index 0000000000000000000000000000000000000000..a36568207b68cfdd556732d89aa1ed0e8eabd26b --- /dev/null +++ b/test/Modules/redecls/module.map @@ -0,0 +1,2 @@ +module a { header "a.h" } +module b { header "b.h" }