From: Francois Pichet Date: Tue, 31 May 2011 11:44:00 +0000 (+0000) Subject: For compatibility with MSVC, a friend declaration also act as a forward declaration... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8adc227de934e23c72eb8d9abf5c0e3dfffec131;p=clang For compatibility with MSVC, a friend declaration also act as a forward declaration if the tag name is not already declared. The tag name is declared in the next outermost non record scope. Example: class A { friend class B; B* b; }; B* global_b; git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@132332 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index a3dd687e3a..8e14207793 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -1084,6 +1084,11 @@ public: bool &OwnedDecl, bool &IsDependent, bool ScopedEnum, bool ScopedEnumUsesClassTag, TypeResult UnderlyingType); + void InjectMicrosoftFriendForwardDeclaration(unsigned TagSpec, + SourceLocation KWLoc, + IdentifierInfo *Name, + SourceLocation NameLoc); + Decl *ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc, unsigned TagSpec, SourceLocation TagLoc, CXXScopeSpec &SS, diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 5a3f6328ca..878c21776d 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -6631,6 +6631,40 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous, return false; } +/// InjectMicrosoftFriendForwardDeclaration - For compatibility with MSVC, +/// a friend declaration also act as a forward declaration if the tag name +/// is not already declared. The tag name is declared in the next outermost +/// non record scope. +/// Example: +/// +/// class A { +/// friend class B; +/// B* b; +/// }; +/// B* global_b; + +void Sema::InjectMicrosoftFriendForwardDeclaration(unsigned TagSpec, + SourceLocation KWLoc, + IdentifierInfo *Name, + SourceLocation NameLoc) { + NamedDecl *N = LookupSingleName(getCurScope(), Name, NameLoc, + Sema::LookupTagName); + if (!N) { + DeclContext *ContextToAdd = CurContext; + while (ContextToAdd->isRecord()) + ContextToAdd = ContextToAdd->getParent(); + + TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec); + TagDecl *New = CXXRecordDecl::Create(Context, Kind, ContextToAdd, KWLoc, + NameLoc, Name, 0); + if (getCurScope()->getFnParent()) + PushOnScopeChains(New, getScopeForContext(ContextToAdd), true); + else + ContextToAdd->addDecl(New); + } +} + + /// ActOnTag - This is invoked when we see 'struct foo' or 'struct {'. In the /// former case, Name will be non-null. In the later case, Name will be null. /// TagSpec indicates what kind of tag this is. TUK indicates whether this is a @@ -6648,6 +6682,9 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, "Nameless record must be a definition!"); assert(TemplateParameterLists.size() == 0 || TUK != TUK_Reference); + if (getLangOptions().Microsoft && TUK == Sema::TUK_Friend) + InjectMicrosoftFriendForwardDeclaration(TagSpec, KWLoc, Name, NameLoc); + OwnedDecl = false; TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec); diff --git a/test/SemaCXX/MicrosoftExtensions.cpp b/test/SemaCXX/MicrosoftExtensions.cpp index 22a06673b9..6d058f2031 100644 --- a/test/SemaCXX/MicrosoftExtensions.cpp +++ b/test/SemaCXX/MicrosoftExtensions.cpp @@ -226,4 +226,29 @@ private: using B::f; // expected-warning {{using declaration refers to inaccessible member 'ms_using_declaration_bug::B::f', which refers to accessible member 'ms_using_declaration_bug::A::f', accepted for Microsoft compatibility}} }; +} + + + +namespace friend_as_a_forward_decl { + +class A { + class Nested { + friend class B; + B* b; + }; + B* b; +}; +B* global_b; + + +void f() +{ + class Local { + friend class Z; + Z* b; + }; + Z* b; +} + } \ No newline at end of file