diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/AST/DeclBase.cpp | 5 | ||||
-rw-r--r-- | lib/AST/DeclCXX.cpp | 26 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 4 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 22 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 230 | ||||
-rw-r--r-- | lib/Sema/SemaLookup.cpp | 13 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 119 |
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, |