diff options
author | John McCall <rjmccall@apple.com> | 2009-10-07 23:34:25 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2009-10-07 23:34:25 +0000 |
commit | e3af0235ce6548e221e04c2ae5aeb0fb413ba736 (patch) | |
tree | 6ed08e7f860ee3261c5388be8bcfa567504e706f | |
parent | 1fef4e60e7e884803977a8376c172ea584f8a5d1 (diff) |
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
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 2 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 67 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 26 | ||||
-rw-r--r-- | test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp | 3 |
4 files changed, 22 insertions, 76 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index a93955be77..3273f2b783 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -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< diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 4743720c62..d612bb8351 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -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)) { diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index b33f8cc835..e00cbf8978 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -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 diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp index 657cf20cf3..b9cdb52f11 100644 --- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp +++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp @@ -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}} |