First->RedeclLink = LatestDeclLink(static_cast<decl_type*>(this));
assert(!isa<NamedDecl>(static_cast<decl_type*>(this)) ||
cast<NamedDecl>(static_cast<decl_type*>(this))->isLinkageValid());
+
+ // If the declaration was previously visible, a redeclaration of it remains
+ // visible even if it wouldn't be visible by itself.
+ static_cast<decl_type*>(this)->IdentifierNamespace |=
+ First->getIdentifierNamespace() &
+ (Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Type);
}
// Inline function definitions.
friend class ASTReader;
friend class LinkageComputer;
+ template<typename decl_type> friend class Redeclarable;
+
private:
void CheckAccessDeclContext() const;
/// class, but in the semantic context of the actual entity. This property
/// applies only to a specific decl object; other redeclarations of the
/// same entity may not (and probably don't) share this property.
- void setObjectOfFriendDecl(bool PreviouslyDeclared) {
+ void setObjectOfFriendDecl(bool PerformFriendInjection = false) {
unsigned OldNS = IdentifierNamespace;
assert((OldNS & (IDNS_Tag | IDNS_Ordinary |
IDNS_TagFriend | IDNS_OrdinaryFriend)) &&
IDNS_TagFriend | IDNS_OrdinaryFriend)) &&
"namespace includes other than ordinary or tag");
+ Decl *Prev = getPreviousDecl();
IdentifierNamespace = 0;
if (OldNS & (IDNS_Tag | IDNS_TagFriend)) {
IdentifierNamespace |= IDNS_TagFriend;
- if (PreviouslyDeclared) IdentifierNamespace |= IDNS_Tag | IDNS_Type;
+ if (PerformFriendInjection ||
+ (Prev && Prev->getIdentifierNamespace() & IDNS_Tag))
+ IdentifierNamespace |= IDNS_Tag | IDNS_Type;
}
if (OldNS & (IDNS_Ordinary | IDNS_OrdinaryFriend)) {
IdentifierNamespace |= IDNS_OrdinaryFriend;
- if (PreviouslyDeclared) IdentifierNamespace |= IDNS_Ordinary;
+ if (PerformFriendInjection ||
+ (Prev && Prev->getIdentifierNamespace() & IDNS_Ordinary))
+ IdentifierNamespace |= IDNS_Ordinary;
}
}
}
if (isFriend) {
- // For now, claim that the objects have no previous declaration.
if (FunctionTemplate) {
- FunctionTemplate->setObjectOfFriendDecl(false);
+ FunctionTemplate->setObjectOfFriendDecl();
FunctionTemplate->setAccess(AS_public);
}
- NewFD->setObjectOfFriendDecl(false);
+ NewFD->setObjectOfFriendDecl();
NewFD->setAccess(AS_public);
}
NewFD->setAccess(Access);
if (FunctionTemplate) FunctionTemplate->setAccess(Access);
-
- PrincipalDecl->setObjectOfFriendDecl(true);
}
if (NewFD->isOverloadedOperator() && !DC->isRecord() &&
// declaration so we always pass true to setObjectOfFriendDecl to make
// the tag name visible.
if (TUK == TUK_Friend)
- New->setObjectOfFriendDecl(/* PreviouslyDeclared = */ !Previous.empty() ||
- (!FriendSawTagOutsideEnclosingNamespace &&
- getLangOpts().MicrosoftExt));
+ New->setObjectOfFriendDecl(!FriendSawTagOutsideEnclosingNamespace &&
+ getLangOpts().MicrosoftExt);
// Set the access specifier.
if (!Invalid && SearchDC->isRecord())
// If the only declaration here is an ordinary friend, consider
// it only if it was declared in an associated classes.
if (D->getIdentifierNamespace() == Decl::IDNS_OrdinaryFriend) {
- DeclContext *LexDC = D->getLexicalDeclContext();
- if (!AssociatedClasses.count(cast<CXXRecordDecl>(LexDC)))
+ bool DeclaredInAssociatedClass = false;
+ for (Decl *DI = D; DI; DI = D->getPreviousDecl()) {
+ DeclContext *LexDC = DI->getLexicalDeclContext();
+ if (AssociatedClasses.count(cast<CXXRecordDecl>(LexDC))) {
+ DeclaredInAssociatedClass = true;
+ break;
+ }
+ }
+ if (!DeclaredInAssociatedClass)
continue;
}
NewClass->setAccess(PrevClassTemplate->getAccess());
}
- NewTemplate->setObjectOfFriendDecl(/* PreviouslyDeclared = */
- PrevClassTemplate != NULL);
+ NewTemplate->setObjectOfFriendDecl();
// Friend templates are visible in fairly strange ways.
if (!CurContext->isDependentContext()) {
else
Inst->setAccess(D->getAccess());
- Inst->setObjectOfFriendDecl(PrevClassTemplate != 0);
+ Inst->setObjectOfFriendDecl();
// TODO: do we want to track the instantiation progeny of this
// friend target decl?
} else {
// If the original function was part of a friend declaration,
// inherit its namespace state.
- if (Decl::FriendObjectKind FOK = D->getFriendObjectKind())
- Record->setObjectOfFriendDecl(FOK == Decl::FOK_Declared);
+ if (D->getFriendObjectKind())
+ Record->setObjectOfFriendDecl();
// Make sure that anonymous structs and unions are recorded.
if (D->isAnonymousStructOrUnion()) {
assert(isFriend && "non-friend has dependent specialization info?");
// This needs to be set now for future sanity.
- Function->setObjectOfFriendDecl(/*HasPrevious*/ true);
+ Function->setObjectOfFriendDecl();
// Instantiate the explicit template arguments.
TemplateArgumentListInfo ExplicitArgs(Info->getLAngleLoc(),
// If the original function was part of a friend declaration,
// inherit its namespace state and add it to the owner.
if (isFriend) {
- NamedDecl *PrevDecl;
- if (TemplateParams)
- PrevDecl = FunctionTemplate->getPreviousDecl();
- else
- PrevDecl = Function->getPreviousDecl();
-
- PrincipalDecl->setObjectOfFriendDecl(PrevDecl != 0);
+ PrincipalDecl->setObjectOfFriendDecl();
DC->makeDeclVisibleInContext(PrincipalDecl);
bool queuedInstantiation = false;
TemplateParams, Method);
if (isFriend) {
FunctionTemplate->setLexicalDeclContext(Owner);
- FunctionTemplate->setObjectOfFriendDecl(true);
+ FunctionTemplate->setObjectOfFriendDecl();
} else if (D->isOutOfLine())
FunctionTemplate->setLexicalDeclContext(D->getLexicalDeclContext());
Method->setDescribedFunctionTemplate(FunctionTemplate);
TempParamLists.data());
Method->setLexicalDeclContext(Owner);
- Method->setObjectOfFriendDecl(true);
+ Method->setObjectOfFriendDecl();
} else if (D->isOutOfLine())
Method->setLexicalDeclContext(D->getLexicalDeclContext());
X2<float> xf;
f(xf);
}
+
+template<typename T>
+struct X3 {
+ operator int();
+
+ friend void h(int x);
+};
+
+int array2[sizeof(X3<int>)];
+int array3[sizeof(X3<float>)];
+
+void i() {
+ X3<int> xi;
+ h(xi);
+ X3<float> xf;
+ h(xf);
+}
friend void C::f(int, int, int) {} // expected-error {{no function named 'f' with type 'void (int, int, int)' was found in the specified scope}}
};
}
+
+namespace test10 {
+ struct A {
+ friend void f10();
+ };
+ struct B {
+ friend void f10();
+ };
+ void g() {
+ f10(); // expected-error {{undeclared identifier}}
+ }
+}