Refactoring around friend class templates. Better error message for friend enums.

Don't create a new declaration for friend classes if a declaration already exists.

llvm-svn: 83505
This commit is contained in:
John McCall 2009-10-07 23:34:25 +00:00
parent 2da7231034
commit c3987485f2
4 changed files with 22 additions and 76 deletions

View File

@ -311,6 +311,8 @@ def err_static_assert_failed : Error<"static_assert failed \"%0\"">;
def err_unexpected_friend : Error<
"friends can only be classes or functions">;
def err_enum_friend : Error<
"enum types cannot be friends">;
def err_friend_is_member : Error<
"friends cannot be members of the declaring class">;
def ext_friend_inner_class : Extension<

View File

@ -1323,71 +1323,29 @@ Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) {
// FIXME: Warn on useless const/volatile
// FIXME: Warn on useless static/extern/typedef/private_extern/mutable
// FIXME: Warn on useless attributes
Decl *TagD = 0;
TagDecl *Tag = 0;
if (DS.getTypeSpecType() == DeclSpec::TST_class ||
DS.getTypeSpecType() == DeclSpec::TST_struct ||
DS.getTypeSpecType() == DeclSpec::TST_union ||
DS.getTypeSpecType() == DeclSpec::TST_enum) {
if (!DS.getTypeRep()) // We probably had an error
TagD = static_cast<Decl *>(DS.getTypeRep());
if (!TagD) // We probably had an error
return DeclPtrTy();
// Note that the above type specs guarantee that the
// type rep is a Decl, whereas in many of the others
// it's a Type.
Tag = dyn_cast<TagDecl>(static_cast<Decl *>(DS.getTypeRep()));
Tag = dyn_cast<TagDecl>(TagD);
}
if (DS.isFriendSpecified()) {
// We have a "friend" declaration that does not have a declarator.
// Look at the type to see if the friend declaration was handled
// elsewhere (e.g., for friend classes and friend class templates).
// If not, produce a suitable diagnostic or go try to befriend the
// type itself.
QualType T;
if (DS.getTypeSpecType() == DeclSpec::TST_typename ||
DS.getTypeSpecType() == DeclSpec::TST_typeofType)
T = QualType::getFromOpaquePtr(DS.getTypeRep());
else if (DS.getTypeSpecType() == DeclSpec::TST_typeofExpr ||
DS.getTypeSpecType() == DeclSpec::TST_decltype)
T = ((Expr *)DS.getTypeRep())->getType();
else if (DS.getTypeSpecType() == DeclSpec::TST_class ||
DS.getTypeSpecType() == DeclSpec::TST_struct ||
DS.getTypeSpecType() == DeclSpec::TST_union)
return DeclPtrTy::make(Tag);
if (T.isNull()) {
// Fall through to diagnose this error, below.
} else if (const RecordType *RecordT = T->getAs<RecordType>()) {
// C++ [class.friend]p2:
// An elaborated-type-specifier shall be used in a friend declaration
// for a class.
// We have something like "friend C;", where C is the name of a
// class type but is missing an elaborated type specifier. Complain,
// but tell the user exactly how to fix the problem.
RecordDecl *RecordD = RecordT->getDecl();
Diag(DS.getTypeSpecTypeLoc(), diag::err_unelaborated_friend_type)
<< (unsigned)RecordD->getTagKind()
<< QualType(RecordT, 0)
<< SourceRange(DS.getFriendSpecLoc())
<< CodeModificationHint::CreateInsertion(DS.getTypeSpecTypeLoc(),
RecordD->getKindName() + std::string(" "));
// FIXME: We could go into ActOnTag to actually make the friend
// declaration happen at this point.
// If we're dealing with a class template decl, assume that the
// template routines are handling it.
if (TagD && isa<ClassTemplateDecl>(TagD))
return DeclPtrTy();
}
if (!T.isNull() && T->isDependentType()) {
// Since T is a dependent type, handle it as a friend type
// declaration.
return ActOnFriendTypeDecl(S, DS, MultiTemplateParamsArg(*this, 0, 0));
}
// Complain about any non-dependent friend type here.
Diag(DS.getFriendSpecLoc(), diag::err_unexpected_friend)
<< DS.getSourceRange();
return DeclPtrTy();
return ActOnFriendTypeDecl(S, DS, MultiTemplateParamsArg(*this, 0, 0));
}
if (RecordDecl *Record = dyn_cast_or_null<RecordDecl>(Tag)) {
@ -4333,14 +4291,9 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// for the consumer of this Decl to know it doesn't own it.
// For our current ASTs this shouldn't be a problem, but will
// need to be changed with DeclGroups.
if (TUK == TUK_Reference)
if (TUK == TUK_Reference || TUK == TUK_Friend)
return DeclPtrTy::make(PrevDecl);
// If this is a friend, make sure we create the new
// declaration in the appropriate semantic context.
if (TUK == TUK_Friend)
SearchDC = PrevDecl->getDeclContext();
// Diagnose attempts to redefine a tag.
if (TUK == TUK_Definition) {
if (TagDecl *Def = PrevTagDecl->getDefinition(Context)) {

View File

@ -4283,8 +4283,10 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S,
std::string InsertionText = std::string(" ") + RD->getKindName();
Diag(DS.getFriendSpecLoc(), diag::err_unelaborated_friend_type)
<< (RD->isUnion())
Diag(DS.getTypeSpecTypeLoc(), diag::err_unelaborated_friend_type)
<< (unsigned) RD->getTagKind()
<< T
<< SourceRange(DS.getFriendSpecLoc())
<< CodeModificationHint::CreateInsertion(DS.getTypeSpecTypeLoc(),
InsertionText);
return DeclPtrTy();
@ -4295,21 +4297,11 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S,
}
}
bool IsDefinition = false;
// 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
// the object of our friend declaration, and we want to disallow
// class definitions.
switch (DS.getTypeSpecType()) {
default: break;
case DeclSpec::TST_class:
case DeclSpec::TST_struct:
case DeclSpec::TST_union:
CXXRecordDecl *RD = cast_or_null<CXXRecordDecl>((Decl*) DS.getTypeRep());
if (RD)
IsDefinition |= RD->isDefinition();
break;
// Enum types cannot be friends.
if (T->getAs<EnumType>()) {
Diag(DS.getTypeSpecTypeLoc(), diag::err_enum_friend)
<< SourceRange(DS.getFriendSpecLoc());
return DeclPtrTy();
}
// C++98 [class.friend]p1: A friend of a class is a function

View File

@ -12,9 +12,8 @@ class A1 {
friend class A;
friend union A; // expected-error {{use of 'A' with tag type that does not match previous declaration}}
// FIXME: a better error would be something like 'enum types cannot be friends'
friend enum A; // expected-error {{ISO C++ forbids forward references to 'enum' types}} \
// expected-error{{classes or functions}}
// expected-error {{enum types cannot be friends}}
};
template <class T> struct B { // expected-note {{previous use is here}}