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:
John McCall 2009-08-11 21:13:21 +00:00
parent cc9ca3500d
commit 2658c4e2d9
5 changed files with 128 additions and 54 deletions

View File

@ -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();
/// ///

View File

@ -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)

View File

@ -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;

View File

@ -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,

View File

@ -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.