зеркало из https://github.com/microsoft/clang-1.git
Improved representation and support for friend class templates. Angst about same.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@82088 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
95f29c2703
Коммит
dd4a3b0065
|
@ -127,6 +127,7 @@ DECL(ObjCForwardProtocol, Decl)
|
|||
DECL(ObjCClass, Decl)
|
||||
DECL(FileScopeAsm, Decl)
|
||||
DECL(Friend, Decl)
|
||||
DECL(FriendTemplate, Decl)
|
||||
DECL(StaticAssert, Decl)
|
||||
LAST_DECL(Block, Decl)
|
||||
|
||||
|
|
|
@ -1227,6 +1227,85 @@ public:
|
|||
virtual void Destroy(ASTContext& C);
|
||||
};
|
||||
|
||||
/// Declaration of a friend template. For example:
|
||||
///
|
||||
/// template <typename T> class A {
|
||||
/// friend class MyVector<T>; // not a friend template
|
||||
/// template <typename U> friend class B; // friend template
|
||||
/// template <typename U> friend class Foo<T>::Nested; // friend template
|
||||
class FriendTemplateDecl : public Decl {
|
||||
public:
|
||||
typedef llvm::PointerUnion<NamedDecl*,Type*> FriendUnion;
|
||||
|
||||
private:
|
||||
// The number of template parameters; always non-zero.
|
||||
unsigned NumParams;
|
||||
|
||||
// The parameter list.
|
||||
TemplateParameterList **Params;
|
||||
|
||||
// The declaration that's a friend of this class.
|
||||
FriendUnion Friend;
|
||||
|
||||
// Location of the 'friend' specifier.
|
||||
SourceLocation FriendLoc;
|
||||
|
||||
|
||||
FriendTemplateDecl(DeclContext *DC, SourceLocation Loc,
|
||||
unsigned NParams,
|
||||
TemplateParameterList **Params,
|
||||
FriendUnion Friend,
|
||||
SourceLocation FriendLoc)
|
||||
: Decl(Decl::FriendTemplate, DC, Loc),
|
||||
NumParams(NParams),
|
||||
Params(Params),
|
||||
Friend(Friend),
|
||||
FriendLoc(FriendLoc)
|
||||
{}
|
||||
|
||||
public:
|
||||
static FriendTemplateDecl *Create(ASTContext &Context,
|
||||
DeclContext *DC, SourceLocation Loc,
|
||||
unsigned NParams,
|
||||
TemplateParameterList **Params,
|
||||
FriendUnion Friend,
|
||||
SourceLocation FriendLoc);
|
||||
|
||||
/// If this friend declaration names a templated type (or
|
||||
/// a dependent member type of a templated type), return that
|
||||
/// type; otherwise return null.
|
||||
Type *getFriendType() const {
|
||||
return Friend.dyn_cast<Type*>();
|
||||
}
|
||||
|
||||
/// If this friend declaration names a templated function (or
|
||||
/// a member function of a templated type), return that type;
|
||||
/// otherwise return null.
|
||||
NamedDecl *getFriendDecl() const {
|
||||
return Friend.dyn_cast<NamedDecl*>();
|
||||
}
|
||||
|
||||
/// Retrieves the location of the 'friend' keyword.
|
||||
SourceLocation getFriendLoc() const {
|
||||
return FriendLoc;
|
||||
}
|
||||
|
||||
TemplateParameterList *getTemplateParameterList(unsigned i) const {
|
||||
assert(i <= NumParams);
|
||||
return Params[i];
|
||||
}
|
||||
|
||||
unsigned getNumTemplateParameters() const {
|
||||
return NumParams;
|
||||
}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) {
|
||||
return D->getKind() == Decl::FriendTemplate;
|
||||
}
|
||||
static bool classof(const FriendTemplateDecl *D) { return true; }
|
||||
};
|
||||
|
||||
/// Implementation of inline functions that require the template declarations
|
||||
inline AnyFunctionDecl::AnyFunctionDecl(FunctionTemplateDecl *FTD)
|
||||
: Function(FTD) { }
|
||||
|
|
|
@ -324,6 +324,8 @@ def err_qualified_friend_not_found : Error<
|
|||
def err_introducing_special_friend : Error<
|
||||
"must use a qualified name when declaring a %select{constructor|"
|
||||
"destructor|conversion operator}0 as a friend">;
|
||||
def err_tagless_friend_type_template : Error<
|
||||
"friend type templates must use an elaborated type">;
|
||||
|
||||
def err_abstract_type_in_decl : Error<
|
||||
"%select{return|parameter|variable|field}0 type %1 is an abstract class">;
|
||||
|
|
|
@ -1215,7 +1215,7 @@ public:
|
|||
/// ActOnFriendTypeDecl - Parsed a friend type declaration.
|
||||
virtual DeclPtrTy ActOnFriendTypeDecl(Scope *S,
|
||||
const DeclSpec &DS,
|
||||
bool IsTemplate) {
|
||||
MultiTemplateParamsArg TParams) {
|
||||
return DeclPtrTy();
|
||||
}
|
||||
|
||||
|
|
|
@ -230,6 +230,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
|
|||
|
||||
// Never have names.
|
||||
case Friend:
|
||||
case FriendTemplate:
|
||||
case LinkageSpec:
|
||||
case FileScopeAsm:
|
||||
case StaticAssert:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
Decl *D;
|
||||
if (TempParams.size())
|
||||
D = FriendTemplateDecl::Create(Context, CurContext, Loc,
|
||||
TempParams.size(),
|
||||
(TemplateParameterList**) TempParams.release(),
|
||||
T.getTypePtr(),
|
||||
DS.getFriendSpecLoc());
|
||||
FD->setAccess(AS_public);
|
||||
CurContext->addDecl(FD);
|
||||
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
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
// RUN: clang-cc -fsyntax-only -verify %s
|
||||
|
||||
template <class T> class A {
|
||||
typedef int Member;
|
||||
};
|
||||
|
||||
class B {
|
||||
template <class T> friend class A;
|
||||
template <class T> friend class Undeclared;
|
||||
template <class T> friend typename A<T>::Member; // expected-error {{friend type templates must use an elaborated type}}
|
||||
};
|
|
@ -1,6 +1,11 @@
|
|||
// RUN: clang-cc -fsyntax-only -verify %s
|
||||
|
||||
class A {
|
||||
template <class T> friend class B;
|
||||
template <class T> class A {
|
||||
class Member {
|
||||
};
|
||||
};
|
||||
|
||||
class B {
|
||||
template <class T> friend class A<T>::Member;
|
||||
};
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче