зеркало из https://github.com/microsoft/clang-1.git
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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@83505 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
1fef4e60e7
Коммит
e3af0235ce
|
@ -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<
|
||||
|
|
|
@ -1323,73 +1323,31 @@ 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();
|
||||
}
|
||||
|
||||
if (RecordDecl *Record = dyn_cast_or_null<RecordDecl>(Tag)) {
|
||||
if (!Record->getDeclName() && Record->isDefinition() &&
|
||||
DS.getStorageClassSpec() != DeclSpec::SCS_typedef) {
|
||||
|
@ -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)) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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}}
|
||||
|
|
Загрузка…
Ссылка в новой задаче