forked from OSchip/llvm-project
Add a FriendClassDecl type for holding declarations of friend types in
the AST, and create such declarations. llvm-svn: 78719
This commit is contained in:
parent
cc9ca3500d
commit
2658c4e2d9
|
@ -1273,6 +1273,42 @@ public:
|
||||||
static bool classof(const FriendFunctionDecl *D) { return true; }
|
static bool classof(const FriendFunctionDecl *D) { return true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// FriendClassDecl - Represents the declaration of a friend class.
|
||||||
|
class FriendClassDecl : public Decl {
|
||||||
|
// The friended type. In C++0x, this can be an arbitrary type,
|
||||||
|
// which we simply ignore if it's not a record type.
|
||||||
|
const QualType FriendType;
|
||||||
|
|
||||||
|
// Location of the 'friend' specifier.
|
||||||
|
const SourceLocation FriendLoc;
|
||||||
|
|
||||||
|
FriendClassDecl(DeclContext *DC, SourceLocation L,
|
||||||
|
QualType T, SourceLocation FriendL)
|
||||||
|
: Decl(FriendClass, DC, L),
|
||||||
|
FriendType(T),
|
||||||
|
FriendLoc(FriendL)
|
||||||
|
{}
|
||||||
|
|
||||||
|
public:
|
||||||
|
static FriendClassDecl *Create(ASTContext &C, DeclContext *DC,
|
||||||
|
SourceLocation L, QualType T,
|
||||||
|
SourceLocation FriendL);
|
||||||
|
|
||||||
|
QualType getFriendType() const {
|
||||||
|
return FriendType;
|
||||||
|
}
|
||||||
|
|
||||||
|
SourceLocation getFriendLoc() const {
|
||||||
|
return FriendLoc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implement isa/cast/dyncast/etc.
|
||||||
|
static bool classof(const Decl *D) {
|
||||||
|
return D->getKind() == FriendClass;
|
||||||
|
}
|
||||||
|
static bool classof(const FriendClassDecl *D) { return true; }
|
||||||
|
};
|
||||||
|
|
||||||
/// LinkageSpecDecl - This represents a linkage specification. For example:
|
/// LinkageSpecDecl - This represents a linkage specification. For example:
|
||||||
/// extern "C" void foo();
|
/// extern "C" void foo();
|
||||||
///
|
///
|
||||||
|
|
|
@ -125,6 +125,7 @@ DECL(ObjCPropertyImpl, Decl)
|
||||||
DECL(ObjCForwardProtocol, Decl)
|
DECL(ObjCForwardProtocol, Decl)
|
||||||
DECL(ObjCClass, Decl)
|
DECL(ObjCClass, Decl)
|
||||||
DECL(FileScopeAsm, Decl)
|
DECL(FileScopeAsm, Decl)
|
||||||
|
DECL(FriendClass, Decl)
|
||||||
DECL(StaticAssert, Decl)
|
DECL(StaticAssert, Decl)
|
||||||
LAST_DECL(Block, Decl)
|
LAST_DECL(Block, Decl)
|
||||||
|
|
||||||
|
|
|
@ -199,6 +199,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
|
||||||
case ObjCCompatibleAlias:
|
case ObjCCompatibleAlias:
|
||||||
return IDNS_Ordinary;
|
return IDNS_Ordinary;
|
||||||
|
|
||||||
|
case FriendClass:
|
||||||
case FriendFunction:
|
case FriendFunction:
|
||||||
return IDNS_Friend;
|
return IDNS_Friend;
|
||||||
|
|
||||||
|
|
|
@ -743,14 +743,20 @@ bool OverloadIterator::Equals(const OverloadIterator &Other) const {
|
||||||
return !isa<OverloadedFunctionDecl>(D) || Iter == Other.Iter;
|
return !isa<OverloadedFunctionDecl>(D) || Iter == Other.Iter;
|
||||||
}
|
}
|
||||||
|
|
||||||
FriendFunctionDecl *FriendFunctionDecl::Create(ASTContext &C,DeclContext *DC,
|
FriendFunctionDecl *FriendFunctionDecl::Create(ASTContext &C,
|
||||||
|
DeclContext *DC,
|
||||||
SourceLocation L,
|
SourceLocation L,
|
||||||
DeclarationName N, QualType T,
|
DeclarationName N, QualType T,
|
||||||
bool isInline,
|
bool isInline,
|
||||||
SourceLocation FriendL) {
|
SourceLocation FriendL) {
|
||||||
return new (C) FriendFunctionDecl(DC, L, N, T, isInline, FriendL);
|
return new (C) FriendFunctionDecl(DC, L, N, T, isInline, FriendL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FriendClassDecl *FriendClassDecl::Create(ASTContext &C, DeclContext *DC,
|
||||||
|
SourceLocation L, QualType T,
|
||||||
|
SourceLocation FriendL) {
|
||||||
|
return new (C) FriendClassDecl(DC, L, T, FriendL);
|
||||||
|
}
|
||||||
|
|
||||||
LinkageSpecDecl *LinkageSpecDecl::Create(ASTContext &C,
|
LinkageSpecDecl *LinkageSpecDecl::Create(ASTContext &C,
|
||||||
DeclContext *DC,
|
DeclContext *DC,
|
||||||
|
|
|
@ -3320,68 +3320,98 @@ Sema::DeclPtrTy Sema::ActOnFriendDecl(Scope *S,
|
||||||
assert(DS.getStorageClassSpec() == DeclSpec::SCS_unspecified);
|
assert(DS.getStorageClassSpec() == DeclSpec::SCS_unspecified);
|
||||||
|
|
||||||
// If there's no declarator, then this can only be a friend class
|
// If there's no declarator, then this can only be a friend class
|
||||||
// declaration (or else it's just invalid).
|
// declaration (or else it's just syntactically invalid).
|
||||||
if (!D) {
|
if (!D) {
|
||||||
|
SourceLocation Loc = DS.getSourceRange().getBegin();
|
||||||
|
|
||||||
// C++ [class.friend]p2:
|
QualType T;
|
||||||
// An elaborated-type-specifier shall be used in a friend declaration
|
DeclContext *DC;
|
||||||
// for a class.*
|
|
||||||
// * The class-key of the elaborated-type-specifier is required.
|
|
||||||
CXXRecordDecl *RD = 0;
|
|
||||||
|
|
||||||
switch (DS.getTypeSpecType()) {
|
// In C++0x, we just accept any old type.
|
||||||
case DeclSpec::TST_class:
|
if (getLangOptions().CPlusPlus0x) {
|
||||||
case DeclSpec::TST_struct:
|
bool invalid = false;
|
||||||
case DeclSpec::TST_union:
|
QualType T = ConvertDeclSpecToType(DS, Loc, invalid);
|
||||||
RD = dyn_cast_or_null<CXXRecordDecl>(static_cast<Decl*>(DS.getTypeRep()));
|
if (invalid)
|
||||||
if (!RD) return DeclPtrTy();
|
return DeclPtrTy();
|
||||||
break;
|
|
||||||
|
|
||||||
case DeclSpec::TST_typename:
|
// The semantic context in which to create the decl. If it's not
|
||||||
if (const RecordType *RT =
|
// a record decl (or we don't yet know if it is), create it in the
|
||||||
((const Type*) DS.getTypeRep())->getAs<RecordType>())
|
// current context.
|
||||||
RD = dyn_cast<CXXRecordDecl>(RT->getDecl());
|
DC = CurContext;
|
||||||
// fallthrough
|
if (const RecordType *RT = T->getAs<RecordType>())
|
||||||
default:
|
DC = RT->getDecl()->getDeclContext();
|
||||||
if (RD) {
|
|
||||||
Diag(DS.getFriendSpecLoc(), diag::err_unelaborated_friend_type)
|
// The C++98 rules are somewhat more complex.
|
||||||
<< (RD->isUnion())
|
} else {
|
||||||
<< CodeModificationHint::CreateInsertion(DS.getTypeSpecTypeLoc(),
|
// C++ [class.friend]p2:
|
||||||
RD->isUnion() ? " union" : " class");
|
// An elaborated-type-specifier shall be used in a friend declaration
|
||||||
return DeclPtrTy::make(RD);
|
// for a class.*
|
||||||
|
// * The class-key of the elaborated-type-specifier is required.
|
||||||
|
CXXRecordDecl *RD = 0;
|
||||||
|
|
||||||
|
switch (DS.getTypeSpecType()) {
|
||||||
|
case DeclSpec::TST_class:
|
||||||
|
case DeclSpec::TST_struct:
|
||||||
|
case DeclSpec::TST_union:
|
||||||
|
RD = dyn_cast_or_null<CXXRecordDecl>((Decl*) DS.getTypeRep());
|
||||||
|
if (!RD) return DeclPtrTy();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DeclSpec::TST_typename:
|
||||||
|
if (const RecordType *RT =
|
||||||
|
((const Type*) DS.getTypeRep())->getAs<RecordType>())
|
||||||
|
RD = dyn_cast<CXXRecordDecl>(RT->getDecl());
|
||||||
|
// fallthrough
|
||||||
|
default:
|
||||||
|
if (RD) {
|
||||||
|
Diag(DS.getFriendSpecLoc(), diag::err_unelaborated_friend_type)
|
||||||
|
<< (RD->isUnion())
|
||||||
|
<< CodeModificationHint::CreateInsertion(DS.getTypeSpecTypeLoc(),
|
||||||
|
RD->isUnion() ? " union" : " class");
|
||||||
|
return DeclPtrTy::make(RD);
|
||||||
|
}
|
||||||
|
|
||||||
|
Diag(DS.getFriendSpecLoc(), diag::err_unexpected_friend)
|
||||||
|
<< DS.getSourceRange();
|
||||||
|
return DeclPtrTy();
|
||||||
}
|
}
|
||||||
|
|
||||||
Diag(DS.getFriendSpecLoc(), diag::err_unexpected_friend)
|
// The record declaration we get from friend declarations is not
|
||||||
<< DS.getSourceRange();
|
// canonicalized; see ActOnTag.
|
||||||
return DeclPtrTy();
|
assert(RD);
|
||||||
|
|
||||||
|
// C++ [class.friend]p2: A class shall not be defined inside
|
||||||
|
// a friend declaration.
|
||||||
|
if (RD->isDefinition())
|
||||||
|
Diag(DS.getFriendSpecLoc(), diag::err_friend_decl_defines_class)
|
||||||
|
<< RD->getSourceRange();
|
||||||
|
|
||||||
|
// C++98 [class.friend]p1: A friend of a class is a function
|
||||||
|
// or class that is not a member of the class . . .
|
||||||
|
// But that's a silly restriction which nobody implements for
|
||||||
|
// inner classes, and C++0x removes it anyway, so we only report
|
||||||
|
// this (as a warning) if we're being pedantic.
|
||||||
|
//
|
||||||
|
// Also, definitions currently get treated in a way that causes
|
||||||
|
// this error, so only report it if we didn't see a definition.
|
||||||
|
else if (RD->getDeclContext() == CurContext &&
|
||||||
|
!getLangOptions().CPlusPlus0x)
|
||||||
|
Diag(DS.getFriendSpecLoc(), diag::ext_friend_inner_class);
|
||||||
|
|
||||||
|
T = QualType(RD->getTypeForDecl(), 0);
|
||||||
|
DC = RD->getDeclContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
// The record declaration we get from friend declarations is not
|
FriendClassDecl *FCD = FriendClassDecl::Create(Context, DC, Loc, T,
|
||||||
// canonicalized; see ActOnTag.
|
DS.getFriendSpecLoc());
|
||||||
assert(RD);
|
FCD->setLexicalDeclContext(CurContext);
|
||||||
|
|
||||||
// C++ [class.friend]p2: A class shall not be defined inside
|
if (CurContext->isDependentContext())
|
||||||
// a friend declaration.
|
CurContext->addHiddenDecl(FCD);
|
||||||
if (RD->isDefinition())
|
else
|
||||||
Diag(DS.getFriendSpecLoc(), diag::err_friend_decl_defines_class)
|
CurContext->addDecl(FCD);
|
||||||
<< RD->getSourceRange();
|
|
||||||
|
|
||||||
// C++98 [class.friend]p1: A friend of a class is a function
|
return DeclPtrTy::make(FCD);
|
||||||
// or class that is not a member of the class . . .
|
|
||||||
// But that's a silly restriction which nobody implements for
|
|
||||||
// inner classes, and C++0x removes it anyway, so we only report
|
|
||||||
// this
|
|
||||||
// But no-one implements it that way, and C++0x removes this
|
|
||||||
// restriction, so we only report it (as a warning) if we're being
|
|
||||||
// pedantic. Ideally this would real -pedantic mode
|
|
||||||
//
|
|
||||||
// Also, definitions currently get treated in a way that causes
|
|
||||||
// this error, so only report it if we didn't see a definition.
|
|
||||||
else if (RD->getDeclContext() == CurContext &&
|
|
||||||
!getLangOptions().CPlusPlus0x)
|
|
||||||
Diag(DS.getFriendSpecLoc(), diag::ext_friend_inner_class);
|
|
||||||
|
|
||||||
return DeclPtrTy::make(RD);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// We have a declarator.
|
// We have a declarator.
|
||||||
|
|
Loading…
Reference in New Issue