[modules] Treat friend declarations that are lexically within a dependent

context as anonymous for merging purposes. They can't be found by their names,
so we merge them based on their position within the surrounding context.

llvm-svn: 228485
This commit is contained in:
Richard Smith 2015-02-07 03:11:11 +00:00
parent 635c2c4378
commit 2b56057517
12 changed files with 83 additions and 24 deletions

View File

@ -846,6 +846,10 @@ bool DeclContext::isDependentContext() const {
return getLexicalParent()->isDependentContext();
}
// FIXME: A variable template is a dependent context, but is not a
// DeclContext. A context within it (such as a lambda-expression)
// should be considered dependent.
return getParent() && getParent()->isDependentContext();
}

View File

@ -223,6 +223,24 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) {
}
bool serialization::needsAnonymousDeclarationNumber(const NamedDecl *D) {
// Friend declarations in dependent contexts aren't anonymous in the usual
// sense, but they cannot be found by name lookup in their semantic context
// (or indeed in any context), so we treat them as anonymous.
//
// This doesn't apply to friend tag decls; Sema makes those available to name
// lookup in the surrounding context.
if (D->getFriendObjectKind() &&
D->getLexicalDeclContext()->isDependentContext() && !isa<TagDecl>(D)) {
// For function templates and class templates, the template is numbered and
// not its pattern.
if (auto *FD = dyn_cast<FunctionDecl>(D))
return !FD->getDescribedFunctionTemplate();
if (auto *RD = dyn_cast<CXXRecordDecl>(D))
return !RD->getDescribedClassTemplate();
return true;
}
// Otherwise, we only care about anonymous class members.
if (D->getDeclName() || !isa<CXXRecordDecl>(D->getLexicalDeclContext()))
return false;
return isa<TagDecl>(D) || isa<FieldDecl>(D);

View File

@ -15,6 +15,7 @@
#define LLVM_CLANG_LIB_SERIALIZATION_ASTCOMMON_H
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclFriend.h"
#include "clang/Serialization/ASTBitCodes.h"
namespace clang {
@ -85,6 +86,24 @@ bool isRedeclarableDeclKind(unsigned Kind);
/// declaration number.
bool needsAnonymousDeclarationNumber(const NamedDecl *D);
/// \brief Visit each declaration within \c DC that needs an anonymous
/// declaration number and call \p Visit with the declaration and its number.
template<typename Fn> void numberAnonymousDeclsWithin(const DeclContext *DC,
Fn Visit) {
unsigned Index = 0;
for (Decl *LexicalD : DC->decls()) {
// For a friend decl, we care about the declaration within it, if any.
if (auto *FD = dyn_cast<FriendDecl>(LexicalD))
LexicalD = FD->getFriendDecl();
auto *ND = dyn_cast_or_null<NamedDecl>(LexicalD);
if (!ND || !needsAnonymousDeclarationNumber(ND))
continue;
Visit(ND, Index++);
}
}
} // namespace serialization
} // namespace clang

View File

@ -478,8 +478,7 @@ void ASTDeclReader::VisitTranslationUnitDecl(TranslationUnitDecl *TU) {
void ASTDeclReader::VisitNamedDecl(NamedDecl *ND) {
VisitDecl(ND);
ND->setDeclName(Reader.ReadDeclarationName(F, Record, Idx));
if (needsAnonymousDeclarationNumber(ND))
AnonymousDeclNumber = Record[Idx++];
AnonymousDeclNumber = Record[Idx++];
}
void ASTDeclReader::VisitTypeDecl(TypeDecl *TD) {
@ -2631,8 +2630,7 @@ ASTDeclReader::FindExistingResult::~FindExistingResult() {
DeclarationName Name = New->getDeclName();
DeclContext *DC = New->getDeclContext()->getRedeclContext();
if (!Name) {
assert(needsAnonymousDeclarationNumber(New));
if (needsAnonymousDeclarationNumber(New)) {
setAnonymousDeclForMerging(Reader, New->getLexicalDeclContext(),
AnonymousDeclNumber, New);
} else if (DC->isTranslationUnit() && Reader.SemaObj) {
@ -2681,17 +2679,12 @@ NamedDecl *ASTDeclReader::getAnonymousDeclForMerging(ASTReader &Reader,
// If this is the first time, but we have parsed a declaration of the context,
// build the anonymous declaration list from the parsed declaration.
if (!cast<Decl>(DC)->isFromASTFile()) {
unsigned Index = 0;
for (Decl *LexicalD : DC->decls()) {
auto *ND = dyn_cast<NamedDecl>(LexicalD);
if (!ND || !needsAnonymousDeclarationNumber(ND))
continue;
if (Previous.size() == Index)
numberAnonymousDeclsWithin(DC, [&](NamedDecl *ND, unsigned Number) {
if (Previous.size() == Number)
Previous.push_back(cast<NamedDecl>(ND->getCanonicalDecl()));
else
Previous[Index] = cast<NamedDecl>(ND->getCanonicalDecl());
++Index;
}
Previous[Number] = cast<NamedDecl>(ND->getCanonicalDecl());
});
}
return Index < Previous.size() ? Previous[Index] : nullptr;
@ -2740,10 +2733,9 @@ ASTDeclReader::FindExistingResult ASTDeclReader::findExisting(NamedDecl *D) {
// was not imported.
}
if (!Name) {
if (needsAnonymousDeclarationNumber(D)) {
// This is an anonymous declaration that we may need to merge. Look it up
// in its context by number.
assert(needsAnonymousDeclarationNumber(D));
if (auto *Existing = getAnonymousDeclForMerging(
Reader, D->getLexicalDeclContext(), AnonymousDeclNumber))
if (isSameEntity(Existing, D))

View File

@ -5226,13 +5226,10 @@ unsigned ASTWriter::getAnonymousDeclarationNumber(const NamedDecl *D) {
// already done so.
auto It = AnonymousDeclarationNumbers.find(D);
if (It == AnonymousDeclarationNumbers.end()) {
unsigned Index = 0;
for (Decl *LexicalD : D->getLexicalDeclContext()->decls()) {
auto *ND = dyn_cast<NamedDecl>(LexicalD);
if (!ND || !needsAnonymousDeclarationNumber(ND))
continue;
AnonymousDeclarationNumbers[ND] = Index++;
}
auto *DC = D->getLexicalDeclContext();
numberAnonymousDeclsWithin(DC, [&](const NamedDecl *ND, unsigned Number) {
AnonymousDeclarationNumbers[ND] = Number;
});
It = AnonymousDeclarationNumbers.find(D);
assert(It != AnonymousDeclarationNumbers.end() &&

View File

@ -203,8 +203,9 @@ void ASTDeclWriter::VisitTranslationUnitDecl(TranslationUnitDecl *D) {
void ASTDeclWriter::VisitNamedDecl(NamedDecl *D) {
VisitDecl(D);
Writer.AddDeclarationName(D->getDeclName(), Record);
if (needsAnonymousDeclarationNumber(D))
Record.push_back(Writer.getAnonymousDeclarationNumber(D));
Record.push_back(needsAnonymousDeclarationNumber(D)
? Writer.getAnonymousDeclarationNumber(D)
: 0);
}
void ASTDeclWriter::VisitTypeDecl(TypeDecl *D) {
@ -1521,6 +1522,7 @@ void ASTWriter::WriteDeclAbbrevs() {
// NamedDecl
Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
Abv->Add(BitCodeAbbrevOp(0)); // AnonDeclNumber
// ValueDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
// DeclaratorDecl
@ -1553,6 +1555,7 @@ void ASTWriter::WriteDeclAbbrevs() {
// NamedDecl
Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
Abv->Add(BitCodeAbbrevOp(0)); // AnonDeclNumber
// ValueDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
// DeclaratorDecl
@ -1590,6 +1593,7 @@ void ASTWriter::WriteDeclAbbrevs() {
// NamedDecl
Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
Abv->Add(BitCodeAbbrevOp(0)); // AnonDeclNumber
// TypeDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Source Location
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type Ref
@ -1637,6 +1641,7 @@ void ASTWriter::WriteDeclAbbrevs() {
// NamedDecl
Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
Abv->Add(BitCodeAbbrevOp(0)); // AnonDeclNumber
// TypeDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Source Location
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type Ref
@ -1679,6 +1684,7 @@ void ASTWriter::WriteDeclAbbrevs() {
// NamedDecl
Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
Abv->Add(BitCodeAbbrevOp(0)); // AnonDeclNumber
// ValueDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
// DeclaratorDecl
@ -1732,6 +1738,7 @@ void ASTWriter::WriteDeclAbbrevs() {
// NamedDecl
Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
Abv->Add(BitCodeAbbrevOp(0)); // AnonDeclNumber
// TypeDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Source Location
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type Ref
@ -1760,6 +1767,7 @@ void ASTWriter::WriteDeclAbbrevs() {
// NamedDecl
Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
Abv->Add(BitCodeAbbrevOp(0)); // AnonDeclNumber
// ValueDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
// DeclaratorDecl
@ -1805,6 +1813,7 @@ void ASTWriter::WriteDeclAbbrevs() {
// NamedDecl
Abv->Add(BitCodeAbbrevOp(DeclarationName::Identifier)); // NameKind
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Identifier
Abv->Add(BitCodeAbbrevOp(0)); // AnonDeclNumber
// ValueDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
// DeclaratorDecl

View File

@ -0,0 +1,2 @@
namespace N { template<typename T> struct A { friend int f(A); }; }
int a = f(N::A<int>());

View File

@ -0,0 +1,2 @@
namespace N { template<typename T> struct A { friend int f(A); }; }
int b = f(N::A<int>());

View File

@ -0,0 +1,6 @@
namespace N { template<typename T> struct A { friend int f(A); }; }
// It would seem like this variable should be called 'c'.
// But that makes the original problem disappear...
int e = f(N::A<int>());
#include "a.h"
#include "b.h"

View File

@ -0,0 +1,2 @@
namespace N { template<typename T> struct A { friend int f(A); }; }
#include "c.h"

View File

@ -0,0 +1,4 @@
module a { header "a.h" export * }
module b { header "b.h" export * }
module c { header "c.h" export * }
module d { header "d.h" export * }

View File

@ -0,0 +1,4 @@
// RUN: rm -rf %t
// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -I%S/Inputs/merge-dependent-friends -verify %s
// expected-no-diagnostics
#include "d.h"