If a template instantation introduces a name into a namespace, we need to write

out a visible update record for that namespace even if it was never declared in
this module.

llvm-svn: 204554
This commit is contained in:
Richard Smith 2014-03-23 02:30:01 +00:00
parent d3415c2440
commit c264d35adc
4 changed files with 24 additions and 0 deletions

View File

@ -176,6 +176,18 @@ void ASTDeclWriter::VisitDecl(Decl *D) {
Record.push_back(D->getAccess());
Record.push_back(D->isModulePrivate());
Record.push_back(Writer.inferSubmoduleIDFromLocation(D->getLocation()));
// If this declaration injected a name into a context different from its
// lexical context, and that context is an imported namespace, we need to
// update its visible declarations to include this name.
//
// This happens when we instantiate a class with a friend declaration or a
// function with a local extern declaration, for instance.
if (D->isOutOfLine()) {
auto *NS = dyn_cast<NamespaceDecl>(D->getDeclContext()->getRedeclContext());
if (NS && NS->isFromASTFile())
Writer.AddUpdatedDeclContext(NS);
}
}
void ASTDeclWriter::VisitTranslationUnitDecl(TranslationUnitDecl *D) {

View File

@ -48,3 +48,5 @@ template<typename T> struct MergeSpecializations<T*> {
template<> struct MergeSpecializations<char> {
typedef int explicitly_specialized_in_a;
};
void InstantiateWithFriend(Std::WithFriend<int> wfi) {}

View File

@ -9,3 +9,9 @@ struct DefinedInCommon {
template<typename T> struct CommonTemplate {
enum E { a = 1, b = 2, c = 3 };
};
namespace Std {
template<typename T> struct WithFriend {
friend bool operator!=(const WithFriend &A, const WithFriend &B) { return false; }
};
}

View File

@ -117,6 +117,10 @@ void testImplicitSpecialMembers(SomeTemplate<char[1]> &a,
c = d;
}
bool testFriendInClassTemplate(Std::WithFriend<int> wfi) {
return wfi != wfi;
}
// CHECK-GLOBAL: DeclarationName 'f'
// CHECK-GLOBAL-NEXT: |-FunctionTemplate {{.*}} 'f'
// CHECK-GLOBAL-NEXT: `-FunctionTemplate {{.*}} 'f'