forked from OSchip/llvm-project
parent
51eeb36c8c
commit
07e91c04ba
|
@ -35,6 +35,7 @@ def err_invalid_short_spec : Error<"'short %0' is invalid">;
|
|||
def err_invalid_long_spec : Error<"'long %0' is invalid">;
|
||||
def err_invalid_longlong_spec : Error<"'long long %0' is invalid">;
|
||||
def err_invalid_complex_spec : Error<"'_Complex %0' is invalid">;
|
||||
def err_friend_storage_spec : Error<"'%0' is invalid in friend declarations">;
|
||||
|
||||
def ext_ident_list_in_param : Extension<
|
||||
"type-less parameter names in function declaration">;
|
||||
|
@ -152,6 +153,8 @@ def err_typename_invalid_functionspec : Error<
|
|||
"type name does not allow function specifier to be specified">;
|
||||
def err_invalid_decl_spec_combination : Error<
|
||||
"cannot combine with previous '%0' declaration specifier">;
|
||||
def err_friend_invalid_in_context : Error<
|
||||
"'friend' used outside of class">;
|
||||
def err_unknown_typename : Error<
|
||||
"unknown type name %0">;
|
||||
def err_use_of_tag_name_without_tag : Error<
|
||||
|
|
|
@ -293,8 +293,20 @@ def err_static_assert_expression_is_not_constant : Error<
|
|||
"static_assert expression is not an integral constant expression">;
|
||||
def err_static_assert_failed : Error<"static_assert failed \"%0\"">;
|
||||
|
||||
def err_friend_decl_outside_class : Error<
|
||||
"'friend' used outside of class">;
|
||||
def err_friend_decl_defines_class : Error<
|
||||
"cannot define a type in a friend declaration">;
|
||||
def err_unexpected_friend : Error<
|
||||
"friends can only be classes or functions">;
|
||||
def err_friend_is_member : Error<
|
||||
"friends cannot be members of the declaring class">;
|
||||
def err_unelaborated_friend_type : Error<
|
||||
"must specify '%select{class|union}0' in a friend "
|
||||
"%select{class|union}0 declaration">;
|
||||
def err_qualified_friend_not_found : Error<
|
||||
"no function named %0 with type %1 was found in the specified scope">;
|
||||
def err_introducing_special_friend : Error<
|
||||
"must use a qualified name when declaring a %select{constructor|"
|
||||
"destructor|conversion operator}0 as a friend">;
|
||||
|
||||
def err_abstract_type_in_decl : Error<
|
||||
"%select{return|parameter|variable|field}1 type %0 is an abstract class">;
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "clang/Parse/DeclSpec.h"
|
||||
#include "clang/Parse/Ownership.h"
|
||||
#include "llvm/Support/PrettyStackTrace.h"
|
||||
#include "llvm/ADT/PointerUnion.h"
|
||||
|
||||
namespace clang {
|
||||
// Semantic.
|
||||
|
@ -413,7 +414,8 @@ public:
|
|||
enum TagUseKind {
|
||||
TUK_Reference, // Reference to a tag: 'struct foo *X;'
|
||||
TUK_Declaration, // Fwd decl of a tag: 'struct foo;'
|
||||
TUK_Definition // Definition of a tag: 'struct foo { int X; } Y;'
|
||||
TUK_Definition, // Definition of a tag: 'struct foo { int X; } Y;'
|
||||
TUK_Friend // Friend declaration: 'friend struct foo;'
|
||||
};
|
||||
|
||||
/// \brief The parser has encountered a tag (e.g., "class X") that should be
|
||||
|
@ -1109,12 +1111,11 @@ public:
|
|||
}
|
||||
|
||||
/// ActOnFriendDecl - This action is called when a friend declaration is
|
||||
/// encountered. Returns false on success.
|
||||
virtual bool ActOnFriendDecl(Scope *S, SourceLocation FriendLoc,
|
||||
DeclPtrTy Dcl) {
|
||||
return false;
|
||||
/// encountered.
|
||||
virtual DeclPtrTy ActOnFriendDecl(Scope *S,
|
||||
llvm::PointerUnion<const DeclSpec*,Declarator*> D) {
|
||||
return DeclPtrTy();
|
||||
}
|
||||
|
||||
|
||||
//===------------------------- C++ Expressions --------------------------===//
|
||||
|
||||
|
|
|
@ -906,6 +906,14 @@ private:
|
|||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// C99 6.7: Declarations.
|
||||
|
||||
/// A context for parsing declaration specifiers. TODO: flesh this
|
||||
/// out, there are other significant restrictions on specifiers than
|
||||
/// would be best implemented in the parser.
|
||||
enum DeclSpecContext {
|
||||
DSC_normal, // normal context
|
||||
DSC_class // class context, enables 'friend'
|
||||
};
|
||||
|
||||
DeclGroupPtrTy ParseDeclaration(unsigned Context, SourceLocation &DeclEnd);
|
||||
DeclGroupPtrTy ParseSimpleDeclaration(unsigned Context,
|
||||
|
@ -922,7 +930,8 @@ private:
|
|||
AccessSpecifier AS);
|
||||
void ParseDeclarationSpecifiers(DeclSpec &DS,
|
||||
const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(),
|
||||
AccessSpecifier AS = AS_none);
|
||||
AccessSpecifier AS = AS_none,
|
||||
DeclSpecContext DSC = DSC_normal);
|
||||
bool ParseOptionalTypeSpecifier(DeclSpec &DS, bool &isInvalid,
|
||||
const char *&PrevSpec,
|
||||
unsigned &DiagID,
|
||||
|
|
|
@ -398,6 +398,24 @@ void DeclSpec::Finish(Diagnostic &D, Preprocessor &PP) {
|
|||
}
|
||||
}
|
||||
|
||||
// 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.
|
||||
|
|
|
@ -27,7 +27,11 @@ Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D) {
|
|||
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);
|
||||
|
||||
|
|
|
@ -708,7 +708,8 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
|
|||
///
|
||||
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 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
|
|||
|
||||
// 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
|
||||
|
|
|
@ -567,15 +567,16 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
|
|||
}
|
||||
}
|
||||
|
||||
// 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 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
|
|||
// 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 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
|
|||
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 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS) {
|
|||
// 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 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS) {
|
|||
// 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);
|
||||
|
||||
|
|
|
@ -1192,6 +1192,9 @@ public:
|
|||
LookupResult LookupQualifiedName(DeclContext *LookupCtx, DeclarationName Name,
|
||||
LookupNameKind NameKind,
|
||||
bool RedeclarationOnly = false);
|
||||
Decl *LookupQualifiedNameWithType(DeclContext *LookupCtx,
|
||||
DeclarationName Name,
|
||||
QualType T);
|
||||
LookupResult LookupParsedName(Scope *S, const CXXScopeSpec *SS,
|
||||
DeclarationName Name,
|
||||
LookupNameKind NameKind,
|
||||
|
@ -2001,8 +2004,8 @@ public:
|
|||
ExprArg AssertExpr,
|
||||
ExprArg AssertMessageExpr);
|
||||
|
||||
virtual bool ActOnFriendDecl(Scope *S, SourceLocation FriendLoc,
|
||||
DeclPtrTy Dcl);
|
||||
virtual DeclPtrTy ActOnFriendDecl(Scope *S,
|
||||
llvm::PointerUnion<const DeclSpec*,Declarator*> D);
|
||||
|
||||
QualType CheckConstructorDeclarator(Declarator &D, QualType R,
|
||||
FunctionDecl::StorageClass& SC);
|
||||
|
|
|
@ -1275,6 +1275,9 @@ Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) {
|
|||
if (!DS.getTypeRep()) // 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()));
|
||||
}
|
||||
|
||||
|
@ -3973,7 +3976,8 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
|
|||
// If this is a use of a previous tag, or if the tag is already declared
|
||||
// in the same scope (so that the definition/declaration completes or
|
||||
// rementions the tag), reuse the decl.
|
||||
if (TUK == TUK_Reference || isDeclInScope(PrevDecl, SearchDC, S)) {
|
||||
if (TUK == TUK_Reference || TUK == TUK_Friend ||
|
||||
isDeclInScope(PrevDecl, SearchDC, S)) {
|
||||
// Make sure that this wasn't declared as an enum and now used as a
|
||||
// struct or something similar.
|
||||
if (!isAcceptableTagRedeclaration(PrevTagDecl, Kind, KWLoc, *Name)) {
|
||||
|
@ -4009,6 +4013,11 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
|
|||
if (TUK == TUK_Reference)
|
||||
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)) {
|
||||
|
@ -4039,7 +4048,8 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
|
|||
}
|
||||
}
|
||||
// If we get here we have (another) forward declaration or we
|
||||
// have a definition. Just create a new decl.
|
||||
// have a definition. Just create a new decl.
|
||||
|
||||
} else {
|
||||
// If we get here, this is a definition of a new tag type in a nested
|
||||
// scope, e.g. "struct foo; void bar() { struct foo; }", just create a
|
||||
|
@ -4102,6 +4112,18 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
|
|||
(S->getEntity() &&
|
||||
((DeclContext *)S->getEntity())->isTransparentContext()))
|
||||
S = S->getParent();
|
||||
|
||||
} else if (TUK == TUK_Friend && SS.isEmpty() && Name) {
|
||||
// C++ [namespace.memdef]p3:
|
||||
// If a friend declaration in a non-local class first declares a
|
||||
// class or function, the friend class or function is a member of
|
||||
// the innermost enclosing namespace.
|
||||
while (!SearchDC->isNamespace() && !SearchDC->isTranslationUnit())
|
||||
SearchDC = SearchDC->getParent();
|
||||
|
||||
// The entity of a decl scope is a DeclContext; see PushDeclContext.
|
||||
while (S->getEntity() != SearchDC)
|
||||
S = S->getParent();
|
||||
}
|
||||
|
||||
CreateNewDecl:
|
||||
|
@ -4195,14 +4217,14 @@ CreateNewDecl:
|
|||
New->setLexicalDeclContext(CurContext);
|
||||
|
||||
// Set the access specifier.
|
||||
if (!Invalid)
|
||||
if (!Invalid && TUK != TUK_Friend)
|
||||
SetMemberAccessSpecifier(New, PrevDecl, AS);
|
||||
|
||||
if (TUK == TUK_Definition)
|
||||
New->startDefinition();
|
||||
|
||||
// If this has an identifier, add it to the scope stack.
|
||||
if (Name) {
|
||||
if (Name && TUK != TUK_Friend) {
|
||||
S = getNonFieldDeclScope(S);
|
||||
PushOnScopeChains(New, S);
|
||||
} else {
|
||||
|
|
|
@ -550,6 +550,8 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
|
|||
|
||||
bool isFunc = D.isFunctionDeclarator();
|
||||
|
||||
assert(!DS.isFriendSpecified());
|
||||
|
||||
// C++ 9.2p6: A member shall not be declared to have automatic storage
|
||||
// duration (auto, register) or with the extern storage-class-specifier.
|
||||
// C++ 7.1.1p8: The mutable specifier can be applied only to names of class
|
||||
|
@ -3302,13 +3304,208 @@ Sema::DeclPtrTy Sema::ActOnStaticAssertDeclaration(SourceLocation AssertLoc,
|
|||
return DeclPtrTy::make(Decl);
|
||||
}
|
||||
|
||||
bool Sema::ActOnFriendDecl(Scope *S, SourceLocation FriendLoc, DeclPtrTy Dcl) {
|
||||
if (!(S->getFlags() & Scope::ClassScope)) {
|
||||
Diag(FriendLoc, diag::err_friend_decl_outside_class);
|
||||
return true;
|
||||
Sema::DeclPtrTy Sema::ActOnFriendDecl(Scope *S,
|
||||
llvm::PointerUnion<const DeclSpec*,Declarator*> DU) {
|
||||
Declarator *D = DU.dyn_cast<Declarator*>();
|
||||
const DeclSpec &DS = (D ? D->getDeclSpec() : *DU.get<const DeclSpec*>());
|
||||
|
||||
assert(DS.isFriendSpecified());
|
||||
assert(DS.getStorageClassSpec() == DeclSpec::SCS_unspecified);
|
||||
|
||||
// If there's no declarator, then this can only be a friend class
|
||||
// declaration (or else it's just invalid).
|
||||
if (!D) {
|
||||
|
||||
// C++ [class.friend]p2:
|
||||
// An elaborated-type-specifier shall be used in a friend declaration
|
||||
// for a class.*
|
||||
// * The class-key of the elaborated-type-specifier is required.
|
||||
CXXRecordDecl *RD = 0;
|
||||
|
||||
switch (DS.getTypeSpecType()) {
|
||||
case DeclSpec::TST_class:
|
||||
case DeclSpec::TST_struct:
|
||||
case DeclSpec::TST_union:
|
||||
RD = dyn_cast_or_null<CXXRecordDecl>(static_cast<Decl*>(DS.getTypeRep()));
|
||||
if (!RD) return DeclPtrTy();
|
||||
break;
|
||||
|
||||
case DeclSpec::TST_typename:
|
||||
if (const RecordType *RT =
|
||||
((const Type*) DS.getTypeRep())->getAs<RecordType>())
|
||||
RD = dyn_cast<CXXRecordDecl>(RT->getDecl());
|
||||
// fallthrough
|
||||
default:
|
||||
if (RD) {
|
||||
Diag(DS.getFriendSpecLoc(), diag::err_unelaborated_friend_type)
|
||||
<< (RD->isUnion())
|
||||
<< CodeModificationHint::CreateInsertion(DS.getTypeSpecTypeLoc(),
|
||||
RD->isUnion() ? " union" : " class");
|
||||
return DeclPtrTy::make(RD);
|
||||
}
|
||||
|
||||
Diag(DS.getFriendSpecLoc(), diag::err_unexpected_friend)
|
||||
<< DS.getSourceRange();
|
||||
return DeclPtrTy();
|
||||
}
|
||||
|
||||
// The record declaration we get from friend declarations is not
|
||||
// canonicalized; see ActOnTag.
|
||||
assert(RD);
|
||||
|
||||
// C++ [class.friend]p2: A class shall not be defined inside
|
||||
// a friend declaration.
|
||||
if (RD->isDefinition())
|
||||
Diag(DS.getFriendSpecLoc(), diag::err_friend_decl_defines_class)
|
||||
<< RD->getSourceRange();
|
||||
|
||||
// C++ [class.friend]p1: A friend of a class is a function or
|
||||
// class that is not a member of the class . . .
|
||||
// Definitions currently get treated in a way that causes this
|
||||
// error, so only report it if we didn't see a definition.
|
||||
else if (RD->getDeclContext() == CurContext)
|
||||
Diag(DS.getFriendSpecLoc(), diag::err_friend_is_member);
|
||||
|
||||
return DeclPtrTy::make(RD);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
// We have a declarator.
|
||||
assert(D);
|
||||
|
||||
SourceLocation Loc = D->getIdentifierLoc();
|
||||
QualType T = GetTypeForDeclarator(*D, S);
|
||||
|
||||
// C++ [class.friend]p1
|
||||
// A friend of a class is a function or class....
|
||||
// Note that this sees through typedefs, which is intended.
|
||||
if (!T->isFunctionType()) {
|
||||
Diag(Loc, diag::err_unexpected_friend);
|
||||
|
||||
// It might be worthwhile to try to recover by creating an
|
||||
// appropriate declaration.
|
||||
return DeclPtrTy();
|
||||
}
|
||||
|
||||
// C++ [namespace.memdef]p3
|
||||
// - If a friend declaration in a non-local class first declares a
|
||||
// class or function, the friend class or function is a member
|
||||
// of the innermost enclosing namespace.
|
||||
// - The name of the friend is not found by simple name lookup
|
||||
// until a matching declaration is provided in that namespace
|
||||
// scope (either before or after the class declaration granting
|
||||
// friendship).
|
||||
// - If a friend function is called, its name may be found by the
|
||||
// name lookup that considers functions from namespaces and
|
||||
// classes associated with the types of the function arguments.
|
||||
// - When looking for a prior declaration of a class or a function
|
||||
// declared as a friend, scopes outside the innermost enclosing
|
||||
// namespace scope are not considered.
|
||||
|
||||
CXXScopeSpec &ScopeQual = D->getCXXScopeSpec();
|
||||
DeclarationName Name = GetNameForDeclarator(*D);
|
||||
assert(Name);
|
||||
|
||||
// The existing declaration we found.
|
||||
FunctionDecl *FD = NULL;
|
||||
|
||||
// The context we found the declaration in, or in which we should
|
||||
// create the declaration.
|
||||
DeclContext *DC;
|
||||
|
||||
// FIXME: handle local classes
|
||||
|
||||
// Recover from invalid scope qualifiers as if they just weren't there.
|
||||
if (!ScopeQual.isInvalid() && ScopeQual.isSet()) {
|
||||
DC = computeDeclContext(ScopeQual);
|
||||
|
||||
// FIXME: handle dependent contexts
|
||||
if (!DC) return DeclPtrTy();
|
||||
|
||||
Decl *Dec = LookupQualifiedNameWithType(DC, Name, T);
|
||||
|
||||
// If searching in that context implicitly found a declaration in
|
||||
// a different context, treat it like it wasn't found at all.
|
||||
// TODO: better diagnostics for this case. Suggesting the right
|
||||
// qualified scope would be nice...
|
||||
if (!Dec || Dec->getDeclContext() != DC) {
|
||||
D->setInvalidType();
|
||||
Diag(Loc, diag::err_qualified_friend_not_found) << Name << T;
|
||||
return DeclPtrTy();
|
||||
}
|
||||
|
||||
// C++ [class.friend]p1: A friend of a class is a function or
|
||||
// class that is not a member of the class . . .
|
||||
if (DC == CurContext)
|
||||
Diag(DS.getFriendSpecLoc(), diag::err_friend_is_member);
|
||||
|
||||
FD = cast<FunctionDecl>(Dec);
|
||||
|
||||
// Otherwise walk out to the nearest namespace scope looking for matches.
|
||||
} else {
|
||||
// TODO: handle local class contexts.
|
||||
|
||||
DC = CurContext;
|
||||
while (true) {
|
||||
// Skip class contexts. If someone can cite chapter and verse
|
||||
// for this behavior, that would be nice --- it's what GCC and
|
||||
// EDG do, and it seems like a reasonable intent, but the spec
|
||||
// really only says that checks for unqualified existing
|
||||
// declarations should stop at the nearest enclosing namespace,
|
||||
// not that they should only consider the nearest enclosing
|
||||
// namespace.
|
||||
while (DC->isRecord()) DC = DC->getParent();
|
||||
|
||||
Decl *Dec = LookupQualifiedNameWithType(DC, Name, T);
|
||||
|
||||
// TODO: decide what we think about using declarations.
|
||||
if (Dec) {
|
||||
FD = cast<FunctionDecl>(Dec);
|
||||
break;
|
||||
}
|
||||
if (DC->isFileContext()) break;
|
||||
DC = DC->getParent();
|
||||
}
|
||||
|
||||
// C++ [class.friend]p1: A friend of a class is a function or
|
||||
// class that is not a member of the class . . .
|
||||
if (FD && DC == CurContext)
|
||||
Diag(DS.getFriendSpecLoc(), diag::err_friend_is_member);
|
||||
}
|
||||
|
||||
// If we didn't find something matching the type exactly, create
|
||||
// a declaration. This declaration should only be findable via
|
||||
// argument-dependent lookup.
|
||||
if (!FD) {
|
||||
assert(DC->isFileContext());
|
||||
|
||||
// This implies that it has to be an operator or function.
|
||||
if (D->getKind() == Declarator::DK_Constructor ||
|
||||
D->getKind() == Declarator::DK_Destructor ||
|
||||
D->getKind() == Declarator::DK_Conversion) {
|
||||
Diag(Loc, diag::err_introducing_special_friend) <<
|
||||
(D->getKind() == Declarator::DK_Constructor ? 0 :
|
||||
D->getKind() == Declarator::DK_Destructor ? 1 : 2);
|
||||
return DeclPtrTy();
|
||||
}
|
||||
|
||||
bool Redeclaration = false;
|
||||
NamedDecl *ND = ActOnFunctionDeclarator(S, *D, DC, T,
|
||||
/* PrevDecl = */ NULL,
|
||||
MultiTemplateParamsArg(*this),
|
||||
/* isFunctionDef */ false,
|
||||
Redeclaration);
|
||||
|
||||
FD = cast_or_null<FunctionDecl>(ND);
|
||||
|
||||
// Note that we're creating a declaration but *not* pushing
|
||||
// it onto the scope chains.
|
||||
|
||||
// TODO: make accessible via argument-dependent lookup.
|
||||
}
|
||||
|
||||
// TODO: actually register the function as a friend.
|
||||
|
||||
return DeclPtrTy::make(FD);
|
||||
}
|
||||
|
||||
void Sema::SetDeclDeleted(DeclPtrTy dcl, SourceLocation DelLoc) {
|
||||
|
|
|
@ -1677,6 +1677,26 @@ ObjCCategoryImplDecl *Sema::LookupObjCCategoryImpl(IdentifierInfo *II) {
|
|||
return cast_or_null<ObjCCategoryImplDecl>(D);
|
||||
}
|
||||
|
||||
// Attempts to find a declaration in the given declaration context
|
||||
// with exactly the given type. Returns null if no such declaration
|
||||
// was found.
|
||||
Decl *Sema::LookupQualifiedNameWithType(DeclContext *DC,
|
||||
DeclarationName Name,
|
||||
QualType T) {
|
||||
LookupResult result =
|
||||
LookupQualifiedName(DC, Name, LookupOrdinaryName, true);
|
||||
|
||||
CanQualType CQT = Context.getCanonicalType(T);
|
||||
|
||||
for (LookupResult::iterator ir = result.begin(), ie = result.end();
|
||||
ir != ie; ++ir)
|
||||
if (FunctionDecl *CurFD = dyn_cast<FunctionDecl>(*ir))
|
||||
if (Context.getCanonicalType(CurFD->getType()) == CQT)
|
||||
return CurFD;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void Sema::LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S,
|
||||
QualType T1, QualType T2,
|
||||
FunctionSet &Functions) {
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
// RUN: clang-cc -fsyntax-only -verify %s
|
||||
// XFAIL
|
||||
|
||||
// FIXME: This part is here to demonstrate the failure in looking up 'f', it can
|
||||
// be removed once the whole test passes.
|
||||
typedef int f;
|
||||
|
||||
namespace N0 {
|
||||
struct A {
|
||||
friend void f();
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
// RUN: clang-cc -fsyntax-only -verify %s
|
||||
|
||||
struct Outer {
|
||||
struct Inner {
|
||||
int intfield;
|
||||
};
|
||||
};
|
||||
|
||||
struct Base {
|
||||
void base_member();
|
||||
|
||||
typedef int Int;
|
||||
Int typedeffed_member();
|
||||
};
|
||||
|
||||
struct Derived : public Base {
|
||||
};
|
||||
|
||||
int myglobal;
|
||||
|
||||
class A {
|
||||
class AInner {
|
||||
};
|
||||
|
||||
friend class PreDeclared;
|
||||
friend class Outer::Inner;
|
||||
friend int Outer::Inner::intfield; // expected-error {{ friends can only be classes or functions }}
|
||||
friend int Outer::Inner::missing_field; //expected-error {{ friends can only be classes or functions }}
|
||||
friend int myoperation(float); // okay
|
||||
friend int myglobal; // expected-error {{ friends can only be classes or functions }}
|
||||
|
||||
void a_member();
|
||||
friend void A::a_member(); // expected-error {{ friends cannot be members of the declaring class }}
|
||||
friend void a_member(); // okay (because we ignore class scopes when looking up friends)
|
||||
friend class A::AInner; // expected-error {{ friends cannot be members of the declaring class }}
|
||||
friend class AInner; // expected-error {{ friends cannot be members of the declaring class }}
|
||||
|
||||
friend void Derived::missing_member(); // expected-error {{ no function named 'missing_member' with type 'void ()' was found in the specified scope }}
|
||||
|
||||
friend void Derived::base_member(); // expected-error {{ no function named 'base_member' with type 'void ()' was found in the specified scope }}
|
||||
|
||||
friend int Base::typedeffed_member(); // okay: should look through typedef
|
||||
|
||||
// These test that the friend is properly not being treated as a
|
||||
// member function.
|
||||
friend A operator|(const A& l, const A& r); // okay
|
||||
friend A operator|(const A& r); // expected-error {{ overloaded 'operator|' must be a binary operator (has 1 parameter) }}
|
||||
|
||||
friend operator bool() const; // expected-error {{ must use a qualified name when declaring a conversion operator as a friend }}
|
||||
|
||||
typedef void ftypedef();
|
||||
friend ftypedef typedeffed_function; // okay (because it's not declared as a member)
|
||||
};
|
||||
|
||||
class PreDeclared;
|
||||
|
||||
int myoperation(float f) {
|
||||
return (int) f;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
// RUN: clang-cc -fsyntax-only -verify %s
|
||||
|
||||
class A {
|
||||
friend class B {}; // expected-error {{cannot define a type in a friend declaration}}
|
||||
friend int; // expected-error {{friends can only be classes or functions}}
|
||||
friend B; // expected-error {{must specify 'class' in a friend class declaration}}
|
||||
friend class C; // okay
|
||||
};
|
|
@ -0,0 +1,10 @@
|
|||
// RUN: clang-cc -fsyntax-only -verify %s
|
||||
|
||||
class A {
|
||||
friend static class B; // expected-error {{'static' is invalid in friend declarations}}
|
||||
friend extern class C; // expected-error {{'extern' is invalid in friend declarations}}
|
||||
friend auto class D; // expected-error {{'auto' is invalid in friend declarations}}
|
||||
friend register class E; // expected-error {{'register' is invalid in friend declarations}}
|
||||
friend mutable class F; // expected-error {{'mutable' is invalid in friend declarations}}
|
||||
friend typedef class G; // expected-error {{'typedef' is invalid in friend declarations}}
|
||||
};
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: clang-cc -fsyntax-only %s
|
||||
// RUN: clang-cc -fsyntax-only -verify %s
|
||||
|
||||
class C {
|
||||
friend class D;
|
||||
|
@ -9,9 +9,24 @@ public:
|
|||
void f();
|
||||
};
|
||||
|
||||
friend int x; // expected-error {{'friend' used outside of class}}
|
||||
|
||||
friend class D {}; // expected-error {{'friend' used outside of class}}
|
||||
|
||||
union U {
|
||||
int u1;
|
||||
};
|
||||
|
||||
class B {
|
||||
// 'A' here should refer to the declaration above.
|
||||
friend class A;
|
||||
|
||||
void f(A *a) { a->f(); }
|
||||
friend C; // expected-error {{must specify 'class' in a friend class declaration}}
|
||||
friend U; // expected-error {{must specify 'union' in a friend union declaration}}
|
||||
friend int; // expected-error {{friends can only be classes or functions}}
|
||||
|
||||
friend void myfunc();
|
||||
|
||||
void f(A *a) { a->f(); }
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue