diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/AST/DeclBase.cpp | 1 | ||||
-rw-r--r-- | clang/lib/AST/DeclTemplate.cpp | 16 | ||||
-rw-r--r-- | clang/lib/Parse/ParseDeclCXX.cpp | 11 | ||||
-rw-r--r-- | clang/lib/Sema/Sema.h | 3 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 6 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 88 |
6 files changed, 84 insertions, 41 deletions
diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index 8d16139fcd3..5f639d807dc 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -230,6 +230,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { // Never have names. case Friend: + case FriendTemplate: case LinkageSpec: case FileScopeAsm: case StaticAssert: diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp index e01cbed20fa..bd1aa7ca9e9 100644 --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -463,3 +463,19 @@ Create(ASTContext &Context, DeclContext *DC, SourceLocation L, Context.getTypeDeclType(Result, PrevDecl); return Result; } + +//===----------------------------------------------------------------------===// +// FriendTemplateDecl Implementation +//===----------------------------------------------------------------------===// + +FriendTemplateDecl *FriendTemplateDecl::Create(ASTContext &Context, + DeclContext *DC, + SourceLocation L, + unsigned NParams, + TemplateParameterList **Params, + FriendUnion Friend, + SourceLocation FLoc) { + FriendTemplateDecl *Result + = new (Context) FriendTemplateDecl(DC, L, NParams, Params, Friend, FLoc); + return Result; +} diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index e1228cf1fdf..671a5421cc1 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -1011,12 +1011,15 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, DeclSpec DS; ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC_class); + Action::MultiTemplateParamsArg TemplateParams(Actions, + TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->data() : 0, + TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->size() : 0); + if (Tok.is(tok::semi)) { ConsumeToken(); if (DS.isFriendSpecified()) { - bool IsTemplate = TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate; - Actions.ActOnFriendTypeDecl(CurScope, DS, IsTemplate); + Actions.ActOnFriendTypeDecl(CurScope, DS, move(TemplateParams)); } else Actions.ParsedFreeStandingDeclSpec(CurScope, DS); @@ -1119,10 +1122,6 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // this call will *not* return the created decl; It will return null. // See Sema::ActOnCXXMemberDeclarator for details. - Action::MultiTemplateParamsArg TemplateParams(Actions, - TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->data() : 0, - TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->size() : 0); - DeclPtrTy ThisDecl; if (DS.isFriendSpecified()) { // TODO: handle initializers, bitfields, 'delete' diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index c078d431524..802dab29d01 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -2248,7 +2248,8 @@ public: ExprArg AssertExpr, ExprArg AssertMessageExpr); - DeclPtrTy ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, bool IsTemplate); + DeclPtrTy ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, + MultiTemplateParamsArg TemplateParams); DeclPtrTy ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition, MultiTemplateParamsArg TemplateParams); diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 696c10a9410..9f86f1233f5 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -3957,7 +3957,11 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, = MatchTemplateParametersToScopeSpecifier(KWLoc, SS, (TemplateParameterList**)TemplateParameterLists.get(), TemplateParameterLists.size())) { - if (TemplateParams->size() > 0) { + if (TUK == TUK_Friend) { + // When declaring a friend template, we do want to match the + // template parameters to the scope specifier, but don't go so far + // as to try to declare a new template. + } else if (TemplateParams->size() > 0) { // This is a declaration or definition of a class template (which may // be a member of another template). OwnedDecl = false; diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index a971b8a281b..61353680399 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -4023,41 +4023,58 @@ Sema::DeclPtrTy Sema::ActOnStaticAssertDeclaration(SourceLocation AssertLoc, return DeclPtrTy::make(Decl); } +/// Handle a friend type declaration. This works in tandem with +/// ActOnTag. +/// +/// Notes on friend class templates: +/// +/// We generally treat friend class declarations as if they were +/// declaring a class. So, for example, the elaborated type specifier +/// in a friend declaration is required to obey the restrictions of a +/// class-head (i.e. no typedefs in the scope chain), template +/// parameters are required to match up with simple template-ids, &c. +/// However, unlike when declaring a template specialization, it's +/// okay to refer to a template specialization without an empty +/// template parameter declaration, e.g. +/// friend class A<T>::B<unsigned>; +/// We permit this as a special case; if there are any template +/// parameters present at all, require proper matching, i.e. +/// template <> template <class T> friend class A<int>::B; Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, - bool IsTemplate) { + MultiTemplateParamsArg TempParams) { SourceLocation Loc = DS.getSourceRange().getBegin(); assert(DS.isFriendSpecified()); assert(DS.getStorageClassSpec() == DeclSpec::SCS_unspecified); - // Handle friend templates specially. - if (IsTemplate) { - Decl *D; - switch (DS.getTypeSpecType()) { - default: - // FIXME: implement this - assert(false && "unelaborated type templates are currently unimplemented!"); - case DeclSpec::TST_class: - case DeclSpec::TST_union: - case DeclSpec::TST_struct: - D = (Decl*) DS.getTypeRep(); - } - - ClassTemplateDecl *Temp = cast<ClassTemplateDecl>(D); - FriendDecl *FD = FriendDecl::Create(Context, CurContext, Loc, Temp, - DS.getFriendSpecLoc()); - FD->setAccess(AS_public); - CurContext->addDecl(FD); - - return DeclPtrTy::make(FD); - } - - // Try to convert the decl specifier to a type. + // Try to convert the decl specifier to a type. This works for + // friend templates because ActOnTag never produces a ClassTemplateDecl + // for a TUK_Friend. bool invalid = false; QualType T = ConvertDeclSpecToType(DS, Loc, invalid); if (invalid) return DeclPtrTy(); + // This is definitely an error in C++98. It's probably meant to + // be forbidden in C++0x, too, but the specification is just + // poorly written. + // + // The problem is with declarations like the following: + // template <T> friend A<T>::foo; + // where deciding whether a class C is a friend or not now hinges + // on whether there exists an instantiation of A that causes + // 'foo' to equal C. There are restrictions on class-heads + // (which we declare (by fiat) elaborated friend declarations to + // be) that makes this tractable. + // + // FIXME: handle "template <> friend class A<T>;", which + // is possibly well-formed? Who even knows? + if (TempParams.size() && !isa<ElaboratedType>(T)) { + Diag(Loc, diag::err_tagless_friend_type_template) + << DS.getSourceRange(); + return DeclPtrTy(); + } + // C++ [class.friend]p2: // An elaborated-type-specifier shall be used in a friend declaration // for a class.* @@ -4085,7 +4102,6 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, } bool IsDefinition = false; - FriendDecl::FriendUnion FU = T.getTypePtr(); // We want to do a few things differently if the type was declared with // a tag: specifically, we want to use the associated RecordDecl as @@ -4097,10 +4113,8 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, case DeclSpec::TST_struct: case DeclSpec::TST_union: CXXRecordDecl *RD = cast_or_null<CXXRecordDecl>((Decl*) DS.getTypeRep()); - if (RD) { + if (RD) IsDefinition |= RD->isDefinition(); - FU = RD; - } break; } @@ -4122,12 +4136,20 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, if (RT->getDecl()->getDeclContext() == CurContext) Diag(DS.getFriendSpecLoc(), diag::ext_friend_inner_class); - FriendDecl *FD = FriendDecl::Create(Context, CurContext, Loc, FU, - DS.getFriendSpecLoc()); - FD->setAccess(AS_public); - CurContext->addDecl(FD); + Decl *D; + if (TempParams.size()) + D = FriendTemplateDecl::Create(Context, CurContext, Loc, + TempParams.size(), + (TemplateParameterList**) TempParams.release(), + T.getTypePtr(), + DS.getFriendSpecLoc()); + else + D = FriendDecl::Create(Context, CurContext, Loc, T.getTypePtr(), + DS.getFriendSpecLoc()); + D->setAccess(AS_public); + CurContext->addDecl(D); - return DeclPtrTy::make(FD); + return DeclPtrTy::make(D); } Sema::DeclPtrTy |