Skeletal support for friend class templates.

llvm-svn: 81801
This commit is contained in:
John McCall 2009-09-14 21:59:20 +00:00
parent b4e19177cb
commit 27b5c253d8
7 changed files with 68 additions and 18 deletions

View File

@ -419,7 +419,8 @@ public:
/// same entity may not (and probably don't) share this property.
void setObjectOfFriendDecl(bool PreviouslyDeclared) {
unsigned OldNS = IdentifierNamespace;
assert((OldNS == IDNS_Tag || OldNS == IDNS_Ordinary)
assert((OldNS == IDNS_Tag || OldNS == IDNS_Ordinary ||
OldNS == (IDNS_Tag | IDNS_Ordinary))
&& "unsupported namespace for undeclared friend");
if (!PreviouslyDeclared) IdentifierNamespace = 0;

View File

@ -1214,7 +1214,8 @@ public:
/// ActOnFriendTypeDecl - Parsed a friend type declaration.
virtual DeclPtrTy ActOnFriendTypeDecl(Scope *S,
const DeclSpec &DS) {
const DeclSpec &DS,
bool IsTemplate) {
return DeclPtrTy();
}

View File

@ -1015,11 +1015,8 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
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);

View File

@ -2246,7 +2246,7 @@ public:
ExprArg AssertExpr,
ExprArg AssertMessageExpr);
DeclPtrTy ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS);
DeclPtrTy ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, bool IsTemplate);
DeclPtrTy ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition,
MultiTemplateParamsArg TemplateParams);

View File

@ -4009,12 +4009,35 @@ Sema::DeclPtrTy Sema::ActOnStaticAssertDeclaration(SourceLocation AssertLoc,
}
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);

View File

@ -556,13 +556,8 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
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) {
@ -657,6 +652,13 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
// 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?
@ -678,7 +680,11 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
(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);
@ -690,7 +696,23 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
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();

View File

@ -0,0 +1,6 @@
// RUN: clang-cc -fsyntax-only -verify %s
class A {
template <class T> friend class B;
};