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();
}
}
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);
#define LLVM_CLANG_LIB_SERIALIZATION_ASTCOMMON_H
#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclFriend.h"
#include "clang/Serialization/ASTBitCodes.h"
namespace clang {
/// 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
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) {
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) {
// 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;
// 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))
// 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() &&
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) {
// 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
// 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
// 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
// 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
// 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
// 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
// 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
// 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
--- /dev/null
+namespace N { template<typename T> struct A { friend int f(A); }; }
+int a = f(N::A<int>());
--- /dev/null
+namespace N { template<typename T> struct A { friend int f(A); }; }
+int b = f(N::A<int>());
--- /dev/null
+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"
--- /dev/null
+namespace N { template<typename T> struct A { friend int f(A); }; }
+#include "c.h"
--- /dev/null
+module a { header "a.h" export * }
+module b { header "b.h" export * }
+module c { header "c.h" export * }
+module d { header "d.h" export * }
--- /dev/null
+// 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"