First pass at friend semantics.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@78274 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Parse/DeclSpec.cpp b/lib/Parse/DeclSpec.cpp
index 8007866..674164a 100644
--- a/lib/Parse/DeclSpec.cpp
+++ b/lib/Parse/DeclSpec.cpp
@@ -398,6 +398,24 @@
}
}
+ // C++ [class.friend]p6:
+ // No storage-class-specifier shall appear in the decl-specifier-seq
+ // of a friend declaration.
+ if (isFriendSpecified() && getStorageClassSpec()) {
+ DeclSpec::SCS SC = getStorageClassSpec();
+ const char *SpecName = getSpecifierName(SC);
+
+ SourceLocation SCLoc = getStorageClassSpecLoc();
+ SourceLocation SCEndLoc = SCLoc.getFileLocWithOffset(strlen(SpecName));
+
+ Diag(D, SCLoc, SrcMgr, diag::err_friend_storage_spec)
+ << SpecName
+ << CodeModificationHint::CreateRemoval(SourceRange(SCLoc, SCEndLoc));
+
+ ClearStorageClassSpecs();
+ }
+
+
// Okay, now we can infer the real type.
// TODO: return "auto function" and other bad things based on the real type.
diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp
index 8afffe3..52a812d 100644
--- a/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/lib/Parse/ParseCXXInlineMethods.cpp
@@ -27,7 +27,11 @@
assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try)) &&
"Current token not a '{', ':' or 'try'!");
- DeclPtrTy FnD = Actions.ActOnCXXMemberDeclarator(CurScope, AS, D, 0, 0);
+ DeclPtrTy FnD;
+ if (D.getDeclSpec().isFriendSpecified())
+ FnD = Actions.ActOnFriendDecl(CurScope, &D);
+ else
+ FnD = Actions.ActOnCXXMemberDeclarator(CurScope, AS, D, 0, 0);
HandleMemberFunctionDefaultArgs(D, FnD);
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 42ef7e6..a80f57c 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -708,7 +708,8 @@
///
void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
const ParsedTemplateInfo &TemplateInfo,
- AccessSpecifier AS) {
+ AccessSpecifier AS,
+ DeclSpecContext DSContext) {
DS.SetRangeStart(Tok.getLocation());
while (1) {
bool isInvalid = false;
@@ -968,7 +969,13 @@
// friend
case tok::kw_friend:
- isInvalid = DS.SetFriendSpec(Loc, PrevSpec, DiagID);
+ if (DSContext == DSC_class)
+ isInvalid = DS.SetFriendSpec(Loc, PrevSpec, DiagID);
+ else {
+ PrevSpec = ""; // not actually used by the diagnostic
+ DiagID = diag::err_friend_invalid_in_context;
+ isInvalid = true;
+ }
break;
// type-specifier
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index c0df8a5..5084d8a 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -567,15 +567,16 @@
}
}
- // There are three options here. If we have 'struct foo;', then
- // this is a forward declaration. If we have 'struct foo {...' or
+ // There are four options here. If we have 'struct foo;', then this
+ // is either a forward declaration or a friend declaration, which
+ // have to be treated differently. If we have 'struct foo {...' or
// 'struct foo :...' then this is a definition. Otherwise we have
// something like 'struct foo xyz', a reference.
Action::TagUseKind TUK;
if (Tok.is(tok::l_brace) || (getLang().CPlusPlus && Tok.is(tok::colon)))
TUK = Action::TUK_Definition;
- else if (Tok.is(tok::semi) && !DS.isFriendSpecified())
- TUK = Action::TUK_Declaration;
+ else if (Tok.is(tok::semi))
+ TUK = DS.isFriendSpecified() ? Action::TUK_Friend : Action::TUK_Declaration;
else
TUK = Action::TUK_Reference;
@@ -600,7 +601,7 @@
// to turn that template-id into a type.
bool Owned = false;
- if (TemplateId && TUK != Action::TUK_Reference) {
+ if (TemplateId && TUK != Action::TUK_Reference && TUK != Action::TUK_Friend) {
// Explicit specialization, class template partial specialization,
// or explicit instantiation.
ASTTemplateArgsPtr TemplateArgsPtr(Actions,
@@ -727,10 +728,6 @@
if (DS.SetTypeSpecType(TagType, StartLoc, PrevSpec, DiagID,
TagOrTempResult.get().getAs<void>(), Owned))
Diag(StartLoc, DiagID) << PrevSpec;
-
- if (DS.isFriendSpecified())
- Actions.ActOnFriendDecl(CurScope, DS.getFriendSpecLoc(),
- TagOrTempResult.get());
}
/// ParseBaseClause - Parse the base-clause of a C++ class [C++ class.derived].
@@ -951,24 +948,17 @@
// decl-specifier-seq:
// Parse the common declaration-specifiers piece.
DeclSpec DS;
- ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS);
+ ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS, DSC_class);
if (Tok.is(tok::semi)) {
ConsumeToken();
- // C++ 9.2p7: The member-declarator-list can be omitted only after a
- // class-specifier or an enum-specifier or in a friend declaration.
- // FIXME: Friend declarations.
- switch (DS.getTypeSpecType()) {
- case DeclSpec::TST_struct:
- case DeclSpec::TST_union:
- case DeclSpec::TST_class:
- case DeclSpec::TST_enum:
+
+ if (DS.isFriendSpecified())
+ Actions.ActOnFriendDecl(CurScope, &DS);
+ else
Actions.ParsedFreeStandingDeclSpec(CurScope, DS);
- return;
- default:
- Diag(DSStart, diag::err_no_declarators);
- return;
- }
+
+ return;
}
Declarator DeclaratorInfo(DS, Declarator::MemberContext);
@@ -1066,11 +1056,17 @@
// NOTE: If Sema is the Action module and declarator is an instance field,
// this call will *not* return the created decl; It will return null.
// See Sema::ActOnCXXMemberDeclarator for details.
- DeclPtrTy ThisDecl = Actions.ActOnCXXMemberDeclarator(CurScope, AS,
- DeclaratorInfo,
- BitfieldSize.release(),
- Init.release(),
- Deleted);
+
+ DeclPtrTy ThisDecl;
+ if (DS.isFriendSpecified()) {
+ // TODO: handle initializers, bitfields, 'delete'
+ ThisDecl = Actions.ActOnFriendDecl(CurScope, &DeclaratorInfo);
+ } else
+ ThisDecl = Actions.ActOnCXXMemberDeclarator(CurScope, AS,
+ DeclaratorInfo,
+ BitfieldSize.release(),
+ Init.release(),
+ Deleted);
if (ThisDecl)
DeclsInGroup.push_back(ThisDecl);