ConsumeToken();
if (DS.isFriendSpecified()) {
- // FIXME: Friend templates are ignored for now.
- if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate)
- return;
-
- Actions.ActOnFriendTypeDecl(CurScope, DS);
+ bool IsTemplate = TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate;
+ Actions.ActOnFriendTypeDecl(CurScope, DS, IsTemplate);
} else
Actions.ParsedFreeStandingDeclSpec(CurScope, DS);
}
Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S,
- const DeclSpec &DS) {
+ const DeclSpec &DS,
+ bool IsTemplate) {
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.
bool invalid = false;
QualType T = ConvertDeclSpecToType(DS, Loc, invalid);
if (CheckTemplateDeclScope(S, TemplateParams))
return true;
- TagDecl::TagKind Kind;
- switch (TagSpec) {
- default: assert(0 && "Unknown tag type!");
- case DeclSpec::TST_struct: Kind = TagDecl::TK_struct; break;
- case DeclSpec::TST_union: Kind = TagDecl::TK_union; break;
- case DeclSpec::TST_class: Kind = TagDecl::TK_class; break;
- }
+ TagDecl::TagKind Kind = TagDecl::getTagKindForTypeSpec(TagSpec);
+ assert(Kind != TagDecl::TK_enum && "can't build template of enumerated type");
// There is no such thing as an unnamed class template.
if (!Name) {
// FIXME: If we had a scope specifier, we better have a previous template
// declaration!
+ // If this is a friend declaration of an undeclared template,
+ // create the template in the innermost namespace scope.
+ if (TUK == TUK_Friend && !PrevClassTemplate) {
+ while (!SemanticContext->isFileContext())
+ SemanticContext = SemanticContext->getParent();
+ }
+
CXXRecordDecl *NewClass =
CXXRecordDecl::Create(Context, Kind, SemanticContext, NameLoc, Name, KWLoc,
PrevClassTemplate?
(void)T;
// Set the access specifier.
- SetMemberAccessSpecifier(NewTemplate, PrevClassTemplate, AS);
+ if (TUK == TUK_Friend)
+ NewTemplate->setObjectOfFriendDecl(/* PreviouslyDeclared = */
+ PrevClassTemplate != NULL);
+ else
+ SetMemberAccessSpecifier(NewTemplate, PrevClassTemplate, AS);
// Set the lexical context of these templates
NewClass->setLexicalDeclContext(CurContext);
if (Attr)
ProcessDeclAttributeList(S, NewClass, Attr);
- PushOnScopeChains(NewTemplate, S);
+ if (TUK != TUK_Friend)
+ PushOnScopeChains(NewTemplate, S);
+ else {
+ // We might be replacing an existing declaration in the lookup tables;
+ // if so, borrow its access specifier.
+ if (PrevClassTemplate)
+ NewTemplate->setAccess(PrevClassTemplate->getAccess());
+
+ // Friend templates are visible in fairly strange ways.
+ if (!CurContext->isDependentContext()) {
+ DeclContext *DC = SemanticContext->getLookupContext();
+ DC->makeDeclVisibleInContext(NewTemplate, /* Recoverable = */ false);
+ if (Scope *EnclosingScope = getScopeForDeclContext(S, DC))
+ PushOnScopeChains(NewTemplate, EnclosingScope,
+ /* AddToContext = */ false);
+ }
+ }
if (Invalid) {
NewTemplate->setInvalidDecl();