From: John McCall Date: Fri, 14 Aug 2009 02:03:10 +0000 (+0000) Subject: Support friend declarations in templates and test that argdep lookup X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=fd810b1386ed29b250e7d522ea826a65c815e49d;p=clang Support friend declarations in templates and test that argdep lookup still works. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@78979 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 86505ee8b0..3212923194 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -44,6 +44,7 @@ namespace { Decl *VisitStaticAssertDecl(StaticAssertDecl *D); Decl *VisitEnumDecl(EnumDecl *D); Decl *VisitEnumConstantDecl(EnumConstantDecl *D); + Decl *VisitFriendClassDecl(FriendClassDecl *D); Decl *VisitFunctionDecl(FunctionDecl *D); Decl *VisitCXXRecordDecl(CXXRecordDecl *D); Decl *VisitCXXMethodDecl(CXXMethodDecl *D); @@ -59,6 +60,10 @@ namespace { return 0; } + const LangOptions &getLangOptions() { + return SemaRef.getLangOptions(); + } + // Helper functions for instantiating methods. QualType InstantiateFunctionType(FunctionDecl *D, llvm::SmallVectorImpl &Params); @@ -211,6 +216,25 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) { return Field; } +Decl *TemplateDeclInstantiator::VisitFriendClassDecl(FriendClassDecl *D) { + QualType T = D->getFriendType(); + if (T->isDependentType()) { + T = SemaRef.InstantiateType(T, TemplateArgs, D->getLocation(), + DeclarationName()); + assert(T.isNull() || getLangOptions().CPlusPlus0x || T->isRecordType()); + } + + // FIXME: the target context might be dependent. + DeclContext *DC = D->getDeclContext(); + assert(DC->isFileContext()); + + FriendClassDecl *NewD = + FriendClassDecl::Create(SemaRef.Context, DC, D->getLocation(), T, + D->getFriendLoc()); + Owner->addDecl(NewD); + return NewD; +} + Decl *TemplateDeclInstantiator::VisitStaticAssertDecl(StaticAssertDecl *D) { Expr *AssertExpr = D->getAssertExpr(); @@ -342,15 +366,30 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D) { QualType T = InstantiateFunctionType(D, Params); if (T.isNull()) return 0; - + // Build the instantiated method declaration. - FunctionDecl *Function - = FunctionDecl::Create(SemaRef.Context, Owner, D->getLocation(), + FunctionDecl *Function; + if (FriendFunctionDecl* FFD = dyn_cast(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->isInline(), + FFD->getFriendLoc()); + Function->setLexicalDeclContext(Owner); + } else { + Function = + FunctionDecl::Create(SemaRef.Context, Owner, D->getLocation(), D->getDeclName(), T, D->getStorageClass(), D->isInline(), D->hasWrittenPrototype(), D->getTypeSpecStartLoc()); - - // FIXME: friend functions + } // Attach the parameters for (unsigned P = 0; P < Params.size(); ++P) @@ -372,7 +411,18 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D) { FunctionTemplate, &TemplateArgs, InsertPos); - } + } + + // If this was a friend function decl, it's a member which + // needs to be added. + if (isa(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; } diff --git a/test/CXX/temp/temp.decls/temp.friend/p1.cpp b/test/CXX/temp/temp.decls/temp.friend/p1.cpp new file mode 100644 index 0000000000..90174585cc --- /dev/null +++ b/test/CXX/temp/temp.decls/temp.friend/p1.cpp @@ -0,0 +1,20 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +template class Num { + T value_; + +public: + Num(T value) : value_(value) {} + T get() const { return value_; } + + friend Num operator+(const Num &a, const Num &b) { + return a.value_ + b.value_; + } +}; + +int main() { + Num left = -1; + Num right = 1; + Num result = left + right; + return result.get(); +}