diff options
author | John McCall <rjmccall@apple.com> | 2009-08-28 07:59:38 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2009-08-28 07:59:38 +0000 |
commit | 02cace78cf48cc26686bd5b07c78606abca13bcd (patch) | |
tree | 6a631652ec93156bd9ed8b2eafd457d8948a607a /lib/Sema/SemaTemplateInstantiateDecl.cpp | |
parent | 550b14b410eaed037c9b791806194e6cea1ebe90 (diff) |
Omnibus friend decl refactoring. Instead of cloning AST classes for friend
declarations of same, introduce a single AST class and add appropriate bits
(encoded in the namespace) for whether a decl is "real" or not. Much hackery
about previously-declared / not-previously-declared, but it's essentially
mandated by the standard that friends alter lookup, and this is at least
fairly non-intrusive.
Refactor the Sema methods specific to friends for cleaner flow and less nesting.
Incidentally solve a few bugs, but I remain confident that we can put them back.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@80353 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaTemplateInstantiateDecl.cpp')
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 119 |
1 files changed, 64 insertions, 55 deletions
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, |