aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/AST/DeclBase.cpp5
-rw-r--r--lib/AST/DeclCXX.cpp26
-rw-r--r--lib/Sema/Sema.h4
-rw-r--r--lib/Sema/SemaDecl.cpp22
-rw-r--r--lib/Sema/SemaDeclCXX.cpp230
-rw-r--r--lib/Sema/SemaLookup.cpp13
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp119
7 files changed, 224 insertions, 195 deletions
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 28d543785f..3ced0eff4c 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -200,10 +200,6 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case ObjCCompatibleAlias:
return IDNS_Ordinary;
- case FriendClass:
- case FriendFunction:
- return IDNS_Friend;
-
case ObjCProtocol:
return IDNS_ObjCProtocol;
@@ -233,6 +229,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
return IDNS_Tag | IDNS_Ordinary;
// Never have names.
+ case Friend:
case LinkageSpec:
case FileScopeAsm:
case StaticAssert:
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 70e48976da..46acf67d29 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -777,20 +777,20 @@ bool OverloadIterator::Equals(const OverloadIterator &Other) const {
return !isa<OverloadedFunctionDecl>(D) || Iter == Other.Iter;
}
-FriendFunctionDecl *FriendFunctionDecl::Create(ASTContext &C,
- DeclContext *DC,
- SourceLocation L,
- DeclarationName N, QualType T,
- DeclaratorInfo *DInfo,
- bool isInline,
- SourceLocation FriendL) {
- return new (C) FriendFunctionDecl(DC, L, N, T, DInfo, isInline, FriendL);
-}
+FriendDecl *FriendDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L,
+ FriendUnion Friend,
+ SourceLocation FriendL) {
+ if (Friend.is<NamedDecl*>()) {
+ NamedDecl *D = Friend.get<NamedDecl*>();
+ assert(isa<FunctionDecl>(D) ||
+ isa<CXXRecordDecl>(D) ||
+ isa<FunctionTemplateDecl>(D) ||
+ isa<ClassTemplateDecl>(D));
+ assert(D->getFriendObjectKind());
+ }
-FriendClassDecl *FriendClassDecl::Create(ASTContext &C, DeclContext *DC,
- SourceLocation L, QualType T,
- SourceLocation FriendL) {
- return new (C) FriendClassDecl(DC, L, T, FriendL);
+ return new (C) FriendDecl(DC, L, Friend, FriendL);
}
LinkageSpecDecl *LinkageSpecDecl::Create(ASTContext &C,
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 905b2e99fd..c59224298a 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -2143,6 +2143,9 @@ public:
virtual DeclPtrTy ActOnFriendDecl(Scope *S,
llvm::PointerUnion<const DeclSpec*,Declarator*> D,
bool IsDefinition);
+ DeclPtrTy ActOnFriendTypeDecl(Scope *S, const DeclSpec& DS,
+ bool IsDefinition);
+ DeclPtrTy ActOnFriendFunctionDecl(Scope *S, Declarator& D, bool IsDefinition);
QualType CheckConstructorDeclarator(Declarator &D, QualType R,
FunctionDecl::StorageClass& SC);
@@ -2955,6 +2958,7 @@ public:
bool Recursive = false);
NamedDecl *FindInstantiatedDecl(NamedDecl *D);
+ DeclContext *FindInstantiatedContext(DeclContext *DC);
// Objective-C declarations.
virtual DeclPtrTy ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 045c12aab5..15e8bc3ab8 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -735,7 +735,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
const CXXMethodDecl* OldMethod = dyn_cast<CXXMethodDecl>(Old);
const CXXMethodDecl* NewMethod = dyn_cast<CXXMethodDecl>(New);
- if (OldMethod && NewMethod &&
+ if (OldMethod && NewMethod && !NewMethod->getFriendObjectKind() &&
NewMethod->getLexicalDeclContext()->isRecord()) {
// -- Member function declarations with the same name and the
// same parameter types cannot be overloaded if any of them
@@ -2411,6 +2411,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
bool isVirtualOkay = false;
FunctionDecl *NewFD;
+
if (isFriend) {
// DC is the namespace in which the function is being declared.
assert((DC->isFileContext() || PrevDecl) && "previously-undeclared "
@@ -2420,13 +2421,9 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// A function can be defined in a friend declaration of a
// class . . . . Such a function is implicitly inline.
isInline |= IsFunctionDefinition;
+ }
- NewFD = FriendFunctionDecl::Create(Context, DC,
- D.getIdentifierLoc(), Name, R, DInfo,
- isInline,
- D.getDeclSpec().getFriendSpecLoc());
-
- } else if (D.getKind() == Declarator::DK_Constructor) {
+ if (D.getKind() == Declarator::DK_Constructor) {
// This is a C++ constructor declaration.
assert(DC->isRecord() &&
"Constructors can only be declared in a member context");
@@ -2514,10 +2511,13 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
NewFD->setInvalidDecl();
// Set the lexical context. If the declarator has a C++
- // scope specifier, the lexical context will be different
- // from the semantic context.
+ // scope specifier, or is the object of a friend declaration, the
+ // lexical context will be different from the semantic context.
NewFD->setLexicalDeclContext(CurContext);
+ if (isFriend)
+ NewFD->setObjectOfFriendDecl(/* PreviouslyDeclared= */ PrevDecl != NULL);
+
// Match up the template parameter lists with the scope specifier, then
// determine whether we have a template or a template specialization.
FunctionTemplateDecl *FunctionTemplate = 0;
@@ -4310,6 +4310,10 @@ CreateNewDecl:
// lexical context will be different from the semantic context.
New->setLexicalDeclContext(CurContext);
+ // Mark this as a friend decl if applicable.
+ if (TUK == TUK_Friend)
+ New->setObjectOfFriendDecl(/* PreviouslyDeclared = */ PrevDecl != NULL);
+
// Set the access specifier.
if (!Invalid && TUK != TUK_Friend)
SetMemberAccessSpecifier(New, PrevDecl, AS);
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 602caf2825..4874c92dec 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -3567,116 +3567,124 @@ Sema::DeclPtrTy Sema::ActOnStaticAssertDeclaration(SourceLocation AssertLoc,
Sema::DeclPtrTy Sema::ActOnFriendDecl(Scope *S,
llvm::PointerUnion<const DeclSpec*,Declarator*> DU,
bool IsDefinition) {
- Declarator *D = DU.dyn_cast<Declarator*>();
- const DeclSpec &DS = (D ? D->getDeclSpec() : *DU.get<const DeclSpec*>());
+ if (DU.is<Declarator*>())
+ return ActOnFriendFunctionDecl(S, *DU.get<Declarator*>(), IsDefinition);
+ else
+ return ActOnFriendTypeDecl(S, *DU.get<const DeclSpec*>(), IsDefinition);
+}
+
+Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S,
+ const DeclSpec &DS,
+ bool IsDefinition) {
+ SourceLocation Loc = DS.getSourceRange().getBegin();
assert(DS.isFriendSpecified());
assert(DS.getStorageClassSpec() == DeclSpec::SCS_unspecified);
- // If there's no declarator, then this can only be a friend class
- // declaration (or else it's just syntactically invalid).
- if (!D) {
- SourceLocation Loc = DS.getSourceRange().getBegin();
-
- QualType T;
- DeclContext *DC;
-
- // In C++0x, we just accept any old type.
- if (getLangOptions().CPlusPlus0x) {
- bool invalid = false;
- QualType T = ConvertDeclSpecToType(DS, Loc, invalid);
- if (invalid)
- return DeclPtrTy();
-
- // The semantic context in which to create the decl. If it's not
- // a record decl (or we don't yet know if it is), create it in the
- // current context.
- DC = CurContext;
- if (const RecordType *RT = T->getAs<RecordType>())
- DC = RT->getDecl()->getDeclContext();
-
- // The C++98 rules are somewhat more complex.
- } else {
- // C++ [class.friend]p2:
- // An elaborated-type-specifier shall be used in a friend declaration
- // for a class.*
- // * The class-key of the elaborated-type-specifier is required.
- CXXRecordDecl *RD = 0;
+ // Check to see if the decl spec was syntactically like "struct foo".
+ RecordDecl *RD = NULL;
+
+ switch (DS.getTypeSpecType()) {
+ case DeclSpec::TST_class:
+ case DeclSpec::TST_struct:
+ case DeclSpec::TST_union:
+ RD = dyn_cast_or_null<CXXRecordDecl>((Decl*) DS.getTypeRep());
+ if (!RD) return DeclPtrTy();
+
+ // The parser doesn't quite handle
+ // friend class A {}
+ // as we'd like, because it might have been the (valid) prefix of
+ // friend class A {} foo();
+ // So even in C++0x mode we don't want to
+ IsDefinition |= RD->isDefinition();
+ break;
+
+ default: break;
+ }
+
+ FriendDecl::FriendUnion FU = RD;
+
+ // C++ [class.friend]p2:
+ // An elaborated-type-specifier shall be used in a friend declaration
+ // for a class.*
+ // * The class-key of the elaborated-type-specifier is required.
+ // So if we didn't get a record decl above, we're invalid in C++98 mode.
+ if (!RD) {
+ bool invalid = false;
+ QualType T = ConvertDeclSpecToType(DS, Loc, invalid);
+ if (invalid) return DeclPtrTy();
- switch (DS.getTypeSpecType()) {
- case DeclSpec::TST_class:
- case DeclSpec::TST_struct:
- case DeclSpec::TST_union:
- RD = dyn_cast_or_null<CXXRecordDecl>((Decl*) DS.getTypeRep());
- if (!RD) return DeclPtrTy();
- break;
-
- case DeclSpec::TST_typename:
- if (const RecordType *RT =
- ((const Type*) DS.getTypeRep())->getAs<RecordType>())
- RD = dyn_cast<CXXRecordDecl>(RT->getDecl());
- // fallthrough
- default:
- if (RD) {
- Diag(DS.getFriendSpecLoc(), diag::err_unelaborated_friend_type)
- << (RD->isUnion())
- << CodeModificationHint::CreateInsertion(DS.getTypeSpecTypeLoc(),
- RD->isUnion() ? " union" : " class");
- return DeclPtrTy::make(RD);
- }
-
- Diag(DS.getFriendSpecLoc(), diag::err_unexpected_friend)
- << DS.getSourceRange();
+ if (const RecordType *RT = T->getAs<RecordType>()) {
+ FU = RD = cast<CXXRecordDecl>(RT->getDecl());
+
+ // Untagged typenames are invalid prior to C++0x, but we can
+ // suggest an easy fix which should work.
+ if (!getLangOptions().CPlusPlus0x) {
+ Diag(DS.getFriendSpecLoc(), diag::err_unelaborated_friend_type)
+ << (RD->isUnion())
+ << CodeModificationHint::CreateInsertion(DS.getTypeSpecTypeLoc(),
+ RD->isUnion() ? " union" : " class");
return DeclPtrTy();
}
-
- // The record declaration we get from friend declarations is not
- // canonicalized; see ActOnTag.
-
- // C++ [class.friend]p2: A class shall not be defined inside
- // a friend declaration.
- if (RD->isDefinition())
- Diag(DS.getFriendSpecLoc(), diag::err_friend_decl_defines_class)
- << RD->getSourceRange();
-
- // C++98 [class.friend]p1: A friend of a class is a function
- // or class that is not a member of the class . . .
- // But that's a silly restriction which nobody implements for
- // inner classes, and C++0x removes it anyway, so we only report
- // this (as a warning) if we're being pedantic.
- //
- // Also, definitions currently get treated in a way that causes
- // this error, so only report it if we didn't see a definition.
- else if (RD->getDeclContext() == CurContext &&
- !getLangOptions().CPlusPlus0x)
- Diag(DS.getFriendSpecLoc(), diag::ext_friend_inner_class);
-
- T = QualType(RD->getTypeForDecl(), 0);
- DC = RD->getDeclContext();
+ }else if (!getLangOptions().CPlusPlus0x) {
+ Diag(DS.getFriendSpecLoc(), diag::err_unexpected_friend)
+ << DS.getSourceRange();
+ return DeclPtrTy();
+ }else {
+ FU = T.getTypePtr();
}
+ }
- FriendClassDecl *FCD = FriendClassDecl::Create(Context, DC, Loc, T,
- DS.getFriendSpecLoc());
- FCD->setLexicalDeclContext(CurContext);
+ assert(FU && "should have a friend decl/type by here!");
- if (CurContext->isDependentContext())
- CurContext->addHiddenDecl(FCD);
- else
- CurContext->addDecl(FCD);
+ // C++ [class.friend]p2: A class shall not be defined inside
+ // a friend declaration.
+ if (IsDefinition) {
+ Diag(DS.getFriendSpecLoc(), diag::err_friend_decl_defines_class)
+ << DS.getSourceRange();
+ return DeclPtrTy();
+ }
- return DeclPtrTy::make(FCD);
+ // C++98 [class.friend]p1: A friend of a class is a function
+ // or class that is not a member of the class . . .
+ // But that's a silly restriction which nobody implements for
+ // inner classes, and C++0x removes it anyway, so we only report
+ // this (as a warning) if we're being pedantic.
+ if (!getLangOptions().CPlusPlus0x) {
+ assert(RD && "must have a record decl in C++98 mode");
+ if (RD->getDeclContext() == CurContext)
+ Diag(DS.getFriendSpecLoc(), diag::ext_friend_inner_class);
}
- // We have a declarator.
- assert(D);
+ FriendDecl *FD = FriendDecl::Create(Context, CurContext, Loc, FU,
+ DS.getFriendSpecLoc());
+ CurContext->addDecl(FD);
- SourceLocation Loc = D->getIdentifierLoc();
+ return DeclPtrTy::make(FD);
+}
+
+Sema::DeclPtrTy Sema::ActOnFriendFunctionDecl(Scope *S,
+ Declarator &D,
+ bool IsDefinition) {
+ const DeclSpec &DS = D.getDeclSpec();
+
+ assert(DS.isFriendSpecified());
+ assert(DS.getStorageClassSpec() == DeclSpec::SCS_unspecified);
+
+ SourceLocation Loc = D.getIdentifierLoc();
DeclaratorInfo *DInfo = 0;
- QualType T = GetTypeForDeclarator(*D, S, &DInfo);
+ QualType T = GetTypeForDeclarator(D, S, &DInfo);
// C++ [class.friend]p1
// A friend of a class is a function or class....
// Note that this sees through typedefs, which is intended.
+ // It *doesn't* see through dependent types, which is correct
+ // according to [temp.arg.type]p3:
+ // If a declaration acquires a function type through a
+ // type dependent on a template-parameter and this causes
+ // a declaration that does not use the syntactic form of a
+ // function declarator to have a function type, the program
+ // is ill-formed.
if (!T->isFunctionType()) {
Diag(Loc, diag::err_unexpected_friend);
@@ -3700,8 +3708,8 @@ Sema::DeclPtrTy Sema::ActOnFriendDecl(Scope *S,
// declared as a friend, scopes outside the innermost enclosing
// namespace scope are not considered.
- CXXScopeSpec &ScopeQual = D->getCXXScopeSpec();
- DeclarationName Name = GetNameForDeclarator(*D);
+ CXXScopeSpec &ScopeQual = D.getCXXScopeSpec();
+ DeclarationName Name = GetNameForDeclarator(D);
assert(Name);
// The existing declaration we found.
@@ -3727,7 +3735,7 @@ Sema::DeclPtrTy Sema::ActOnFriendDecl(Scope *S,
// TODO: better diagnostics for this case. Suggesting the right
// qualified scope would be nice...
if (!Dec || Dec->getDeclContext() != DC) {
- D->setInvalidType();
+ D.setInvalidType();
Diag(Loc, diag::err_qualified_friend_not_found) << Name << T;
return DeclPtrTy();
}
@@ -3789,36 +3797,36 @@ Sema::DeclPtrTy Sema::ActOnFriendDecl(Scope *S,
assert(DC->isFileContext());
// This implies that it has to be an operator or function.
- if (D->getKind() == Declarator::DK_Constructor ||
- D->getKind() == Declarator::DK_Destructor ||
- D->getKind() == Declarator::DK_Conversion) {
+ if (D.getKind() == Declarator::DK_Constructor ||
+ D.getKind() == Declarator::DK_Destructor ||
+ D.getKind() == Declarator::DK_Conversion) {
Diag(Loc, diag::err_introducing_special_friend) <<
- (D->getKind() == Declarator::DK_Constructor ? 0 :
- D->getKind() == Declarator::DK_Destructor ? 1 : 2);
+ (D.getKind() == Declarator::DK_Constructor ? 0 :
+ D.getKind() == Declarator::DK_Destructor ? 1 : 2);
return DeclPtrTy();
}
}
- NamedDecl *ND = ActOnFunctionDeclarator(S, *D, DC, T, DInfo,
+ NamedDecl *ND = ActOnFunctionDeclarator(S, D, DC, T, DInfo,
/* PrevDecl = */ FD,
MultiTemplateParamsArg(*this),
IsDefinition,
Redeclaration);
- FD = cast_or_null<FriendFunctionDecl>(ND);
+ if (!ND) return DeclPtrTy();
+ FD = cast<FunctionDecl>(ND);
assert(FD->getDeclContext() == DC);
assert(FD->getLexicalDeclContext() == CurContext);
- // If this is a dependent context, just add the decl to the
- // class's decl list and don't both with the lookup tables. This
- // doesn't affect lookup because any call that might find this
- // function via ADL necessarily has to involve dependently-typed
- // arguments and hence can't be resolved until
- // template-instantiation anyway.
- if (CurContext->isDependentContext())
- CurContext->addHiddenDecl(FD);
- else
- CurContext->addDecl(FD);
+ // We only add the function declaration to the lookup tables, not
+ // the decl list, and only if the context isn't dependent.
+ if (!CurContext->isDependentContext())
+ DC->makeDeclVisibleInContext(FD);
+
+ FriendDecl *FrD = FriendDecl::Create(Context, CurContext,
+ D.getIdentifierLoc(), FD,
+ DS.getFriendSpecLoc());
+ CurContext->addDecl(FrD);
return DeclPtrTy::make(FD);
}
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index 6627499d12..4a699de6c8 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -643,6 +643,13 @@ Sema::CppLookupName(Scope *S, DeclarationName Name,
"Can perform only C++ lookup");
unsigned IDNS
= getIdentifierNamespacesFromLookupNameKind(NameKind, /*CPlusPlus*/ true);
+
+ // If we're testing for redeclarations, also look in the friend namespaces.
+ if (RedeclarationOnly) {
+ if (IDNS & Decl::IDNS_Tag) IDNS |= Decl::IDNS_TagFriend;
+ if (IDNS & Decl::IDNS_Ordinary) IDNS |= Decl::IDNS_OrdinaryFriend;
+ }
+
Scope *Initial = S;
DeclContext *OutOfLineCtx = 0;
IdentifierResolver::iterator
@@ -1769,9 +1776,9 @@ void Sema::ArgumentDependentLookup(DeclarationName Name,
DeclContext::lookup_iterator I, E;
for (llvm::tie(I, E) = (*NS)->lookup(Name); I != E; ++I) {
Decl *D = *I;
- // Only count friend declarations which were declared in
- // associated classes.
- if (D->isInIdentifierNamespace(Decl::IDNS_Friend)) {
+ // 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)))
continue;
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index a0353e3c53..0bf832f3eb 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -45,7 +45,7 @@ namespace {
Decl *VisitStaticAssertDecl(StaticAssertDecl *D);
Decl *VisitEnumDecl(EnumDecl *D);
Decl *VisitEnumConstantDecl(EnumConstantDecl *D);
- Decl *VisitFriendClassDecl(FriendClassDecl *D);
+ Decl *VisitFriendDecl(FriendDecl *D);
Decl *VisitFunctionDecl(FunctionDecl *D);
Decl *VisitCXXRecordDecl(CXXRecordDecl *D);
Decl *VisitCXXMethodDecl(CXXMethodDecl *D,
@@ -250,25 +250,35 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) {
return Field;
}
-Decl *TemplateDeclInstantiator::VisitFriendClassDecl(FriendClassDecl *D) {
- QualType T = D->getFriendType();
- if (T->isDependentType()) {
- T = SemaRef.SubstType(T, TemplateArgs, D->getLocation(),
- DeclarationName());
- assert(T.isNull() || getLangOptions().CPlusPlus0x || T->isRecordType());
- }
+Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) {
+ FriendDecl::FriendUnion FU;
+
+ // Handle friend type expressions by simply substituting template
+ // parameters into the pattern type.
+ if (Type *Ty = D->getFriendType()) {
+ QualType T = SemaRef.SubstType(QualType(Ty,0), TemplateArgs,
+ D->getLocation(), DeclarationName());
+ if (T.isNull()) return 0;
- // FIXME: the target context might be dependent.
- DeclContext *DC = D->getDeclContext();
- assert(DC->isFileContext());
+ assert(getLangOptions().CPlusPlus0x || T->isRecordType());
+ FU = T.getTypePtr();
- FriendClassDecl *NewD =
- FriendClassDecl::Create(SemaRef.Context, DC, D->getLocation(), T,
- D->getFriendLoc());
- NewD->setLexicalDeclContext(Owner);
+ // Handle everything else by appropriate substitution.
+ } else {
+ NamedDecl *ND = D->getFriendDecl();
+ assert(ND && "friend decl must be a decl or a type!");
+
+ Decl *NewND = Visit(ND);
+ if (!NewND) return 0;
- Owner->addDecl(NewD);
- return NewD;
+ FU = cast<NamedDecl>(NewND);
+ }
+
+ FriendDecl *FD =
+ FriendDecl::Create(SemaRef.Context, Owner, D->getLocation(), FU,
+ D->getFriendLoc());
+ Owner->addDecl(FD);
+ return FD;
}
Decl *TemplateDeclInstantiator::VisitStaticAssertDecl(StaticAssertDecl *D) {
@@ -424,10 +434,20 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) {
if (!D->isInjectedClassName())
Record->setInstantiationOfMemberClass(D);
+ // 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);
+
Owner->addDecl(Record);
return Record;
}
+/// Normal class members are of more specific types and therefore
+/// don't make it here. This function serves two purposes:
+/// 1) instantiating function templates
+/// 2) substituting friend declarations
+/// FIXME: preserve function definitions in case #2
Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D) {
// Check whether there is already a function template specialization for
// this declaration.
@@ -457,33 +477,27 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D) {
return 0;
// Build the instantiated method declaration.
- FunctionDecl *Function;
- if (FriendFunctionDecl* FFD = dyn_cast<FriendFunctionDecl>(D)) {
- // The new decl's semantic context. FIXME: this might need
- // to be instantiated.
- DeclContext *DC = D->getDeclContext();
-
- // This assert is bogus and exists only to catch cases we don't
- // handle yet.
- assert(!DC->isDependentContext());
-
- Function =
- FriendFunctionDecl::Create(SemaRef.Context, DC, D->getLocation(),
- D->getDeclName(), T, D->getDeclaratorInfo(),
- D->isInline(), FFD->getFriendLoc());
- Function->setLexicalDeclContext(Owner);
- } else {
- Function =
- FunctionDecl::Create(SemaRef.Context, Owner, D->getLocation(),
+ DeclContext *DC = SemaRef.FindInstantiatedContext(D->getDeclContext());
+ FunctionDecl *Function =
+ FunctionDecl::Create(SemaRef.Context, DC, D->getLocation(),
D->getDeclName(), T, D->getDeclaratorInfo(),
D->getStorageClass(),
D->isInline(), D->hasWrittenPrototype());
- }
-
+ Function->setLexicalDeclContext(Owner);
+
// Attach the parameters
for (unsigned P = 0; P < Params.size(); ++P)
Params[P]->setOwningFunction(Function);
Function->setParams(SemaRef.Context, Params.data(), Params.size());
+
+ // If the original function was part of a friend declaration,
+ // inherit its namespace state and add it to the owner.
+ if (Decl::FriendObjectKind FOK = D->getFriendObjectKind()) {
+ bool WasDeclared = (FOK == Decl::FOK_Declared);
+ Function->setObjectOfFriendDecl(WasDeclared);
+ if (!Owner->isDependentContext())
+ DC->makeDeclVisibleInContext(Function);
+ }
if (InitFunctionInstantiation(Function, D))
Function->setInvalidDecl();
@@ -502,17 +516,6 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D) {
InsertPos);
}
- // If this was a friend function decl, it's a member which
- // needs to be added.
- if (isa<FriendFunctionDecl>(Function)) {
- // If the new context is still dependent, this declaration
- // needs to remain hidden.
- if (Owner->isDependentContext())
- Owner->addHiddenDecl(Function);
- else
- Owner->addDecl(Function);
- }
-
return Function;
}
@@ -1127,6 +1130,17 @@ static NamedDecl *findInstantiationOf(ASTContext &Ctx,
return 0;
}
+/// \brief Finds the instantiation of the given declaration context
+/// within the current instantiation.
+///
+/// \returns NULL if there was an error
+DeclContext *Sema::FindInstantiatedContext(DeclContext* DC) {
+ if (NamedDecl *D = dyn_cast<NamedDecl>(DC)) {
+ Decl* ID = FindInstantiatedDecl(D);
+ return cast_or_null<DeclContext>(ID);
+ } else return DC;
+}
+
/// \brief Find the instantiation of the given declaration within the
/// current instantiation.
///
@@ -1161,13 +1175,8 @@ NamedDecl * Sema::FindInstantiatedDecl(NamedDecl *D) {
return cast<NamedDecl>(CurrentInstantiationScope->getInstantiationOf(D));
}
- if (NamedDecl *ParentDecl = dyn_cast<NamedDecl>(ParentDC)) {
- ParentDecl = FindInstantiatedDecl(ParentDecl);
- if (!ParentDecl)
- return 0;
-
- ParentDC = cast<DeclContext>(ParentDecl);
- }
+ ParentDC = FindInstantiatedContext(ParentDC);
+ if (!ParentDC) return 0;
if (ParentDC != D->getDeclContext()) {
// We performed some kind of instantiation in the parent context,