diff options
Diffstat (limited to 'lib/Sema')
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 61 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 8 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 40 |
3 files changed, 81 insertions, 28 deletions
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 1f53cde64b..f8751fb9c9 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -1288,6 +1288,59 @@ Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) { Tag = dyn_cast<TagDecl>(static_cast<Decl *>(DS.getTypeRep())); } + 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. + 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(); + } + if (RecordDecl *Record = dyn_cast_or_null<RecordDecl>(Tag)) { if (!Record->getDeclName() && Record->isDefinition() && DS.getStorageClassSpec() != DeclSpec::SCS_typedef) { @@ -1305,7 +1358,7 @@ Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) { if (Record->getDeclName() && getLangOptions().Microsoft) return DeclPtrTy::make(Tag); } - + if (!DS.isMissingDeclaratorOk() && DS.getTypeSpecType() != DeclSpec::TST_error) { // Warn about typedefs of enums without names, since this is an @@ -4022,11 +4075,7 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, = MatchTemplateParametersToScopeSpecifier(KWLoc, SS, (TemplateParameterList**)TemplateParameterLists.get(), TemplateParameterLists.size())) { - if (TUK == TUK_Friend) { - // When declaring a friend template, we do want to match the - // template parameters to the scope specifier, but don't go so far - // as to try to declare a new template. - } else if (TemplateParams->size() > 0) { + if (TemplateParams->size() > 0) { // This is a declaration or definition of a class template (which may // be a member of another template). OwnedDecl = false; diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 390a8048db..02c1a08c8f 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -4141,14 +4141,6 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, break; } - // C++ [class.friend]p2: A class shall not be defined inside - // a friend declaration. - if (IsDefinition) { - Diag(DS.getFriendSpecLoc(), diag::err_friend_decl_defines_class) - << DS.getSourceRange(); - return DeclPtrTy(); - } - // C++98 [class.friend]p1: A friend of a class is a function // or class that is not a member of the class . . . // But that's a silly restriction which nobody implements for diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index d5fb7e82a8..72274525fd 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -579,6 +579,18 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, Previous = LookupQualifiedName(SemanticContext, Name, LookupOrdinaryName, true); + } else if (TUK == TUK_Friend) { + // C++ [namespace.memdef]p3: + // [...] When looking for a prior declaration of a class or a function + // declared as a friend, and when the name of the friend class or + // function is neither a qualified name nor a template-id, scopes outside + // the innermost enclosing namespace scope are not considered. + SemanticContext = CurContext; + while (!SemanticContext->isFileContext()) + SemanticContext = SemanticContext->getLookupParent(); + + Previous = LookupQualifiedName(SemanticContext, Name, LookupOrdinaryName, + true); } else { SemanticContext = CurContext; Previous = LookupName(S, Name, LookupOrdinaryName, true); @@ -654,13 +666,6 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, // FIXME: If we had a scope specifier, we better have a previous template // declaration! - // If this is a friend declaration of an undeclared template, - // create the template in the innermost namespace scope. - if (TUK == TUK_Friend && !PrevClassTemplate) { - while (!SemanticContext->isFileContext()) - SemanticContext = SemanticContext->getParent(); - } - CXXRecordDecl *NewClass = CXXRecordDecl::Create(Context, Kind, SemanticContext, NameLoc, Name, KWLoc, PrevClassTemplate? @@ -682,10 +687,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, (void)T; // Set the access specifier. - if (TUK == TUK_Friend) - NewTemplate->setObjectOfFriendDecl(/* PreviouslyDeclared = */ - PrevClassTemplate != NULL); - else + if (!Invalid && TUK != TUK_Friend) SetMemberAccessSpecifier(NewTemplate, PrevClassTemplate, AS); // Set the lexical context of these templates @@ -701,11 +703,14 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, if (TUK != TUK_Friend) PushOnScopeChains(NewTemplate, S); else { - // We might be replacing an existing declaration in the lookup tables; - // if so, borrow its access specifier. - if (PrevClassTemplate) + if (PrevClassTemplate && PrevClassTemplate->getAccess() != AS_none) { NewTemplate->setAccess(PrevClassTemplate->getAccess()); + NewClass->setAccess(PrevClassTemplate->getAccess()); + } + NewTemplate->setObjectOfFriendDecl(/* PreviouslyDeclared = */ + PrevClassTemplate != NULL); + // Friend templates are visible in fairly strange ways. if (!CurContext->isDependentContext()) { DeclContext *DC = SemanticContext->getLookupContext(); @@ -714,6 +719,13 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, PushOnScopeChains(NewTemplate, EnclosingScope, /* AddToContext = */ false); } + + FriendDecl *Friend = FriendDecl::Create(Context, CurContext, + NewClass->getLocation(), + NewTemplate, + /*FIXME:*/NewClass->getLocation()); + Friend->setAccess(AS_public); + CurContext->addDecl(Friend); } if (Invalid) { |