aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrancois Pichet <pichet2000@gmail.com>2011-05-31 11:44:00 +0000
committerFrancois Pichet <pichet2000@gmail.com>2011-05-31 11:44:00 +0000
commit8adc227de934e23c72eb8d9abf5c0e3dfffec131 (patch)
tree3a4272584e5463a2671bed9d408c766b3880ff03
parent8155910a192dafa423d6b932b7d127d48e4641e8 (diff)
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
-rw-r--r--include/clang/Sema/Sema.h5
-rw-r--r--lib/Sema/SemaDecl.cpp37
-rw-r--r--test/SemaCXX/MicrosoftExtensions.cpp25
3 files changed, 67 insertions, 0 deletions
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