diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/Sema/SemaAccess.cpp | 57 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 6 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiate.cpp | 3 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 48 |
4 files changed, 79 insertions, 35 deletions
diff --git a/clang/lib/Sema/SemaAccess.cpp b/clang/lib/Sema/SemaAccess.cpp index f71a38816f6..3481171c773 100644 --- a/clang/lib/Sema/SemaAccess.cpp +++ b/clang/lib/Sema/SemaAccess.cpp @@ -1632,25 +1632,6 @@ Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc, return CheckAccess(*this, UseLoc, AccessEntity); } -/// Checks direct (i.e. non-inherited) access to an arbitrary class -/// member. -Sema::AccessResult Sema::CheckDirectMemberAccess(SourceLocation UseLoc, - NamedDecl *Target, - const PartialDiagnostic &Diag) { - AccessSpecifier Access = Target->getAccess(); - if (!getLangOpts().AccessControl || - Access == AS_public) - return AR_accessible; - - CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(Target->getDeclContext()); - AccessTarget Entity(Context, AccessTarget::Member, NamingClass, - DeclAccessPair::make(Target, Access), - QualType()); - Entity.setDiag(Diag); - return CheckAccess(*this, UseLoc, Entity); -} - - /// Checks access to an overloaded operator new or delete. Sema::AccessResult Sema::CheckAllocationAccess(SourceLocation OpLoc, SourceRange PlacementRange, @@ -1693,6 +1674,44 @@ Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc, return CheckAccess(*this, OpLoc, Entity); } +/// Checks access to the target of a friend declaration. +Sema::AccessResult Sema::CheckFriendAccess(NamedDecl *target) { + assert(isa<CXXMethodDecl>(target) || + (isa<FunctionTemplateDecl>(target) && + isa<CXXMethodDecl>(cast<FunctionTemplateDecl>(target) + ->getTemplatedDecl()))); + + // Friendship lookup is a redeclaration lookup, so there's never an + // inheritance path modifying access. + AccessSpecifier access = target->getAccess(); + + if (!getLangOpts().AccessControl || access == AS_public) + return AR_accessible; + + CXXMethodDecl *method = dyn_cast<CXXMethodDecl>(target); + if (!method) + method = cast<CXXMethodDecl>( + cast<FunctionTemplateDecl>(target)->getTemplatedDecl()); + assert(method->getQualifier()); + + AccessTarget entity(Context, AccessTarget::Member, + cast<CXXRecordDecl>(target->getDeclContext()), + DeclAccessPair::make(target, access), + /*no instance context*/ QualType()); + entity.setDiag(diag::err_access_friend_function) + << method->getQualifierLoc().getSourceRange(); + + // We need to bypass delayed-diagnostics because we might be called + // while the ParsingDeclarator is active. + EffectiveContext EC(CurContext); + switch (CheckEffectiveAccess(*this, EC, target->getLocation(), entity)) { + case AR_accessible: return Sema::AR_accessible; + case AR_inaccessible: return Sema::AR_inaccessible; + case AR_dependent: return Sema::AR_dependent; + } + llvm_unreachable("falling off end"); +} + Sema::AccessResult Sema::CheckAddressOfMemberAccess(Expr *OvlExpr, DeclAccessPair Found) { if (!getLangOpts().AccessControl || diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index c259c8125ac..539ed0eac56 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -10342,9 +10342,11 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, FrD->setAccess(AS_public); CurContext->addDecl(FrD); - if (ND->isInvalidDecl()) + if (ND->isInvalidDecl()) { FrD->setInvalidDecl(); - else { + } else { + if (DC->isRecord()) CheckFriendAccess(ND); + FunctionDecl *FD; if (FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(ND)) FD = FTD->getTemplatedDecl(); diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 102ec993ef3..c7cbc41b303 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -2005,6 +2005,9 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, } if (!Instantiation->isInvalidDecl()) { + // Perform any dependent diagnostics from the pattern. + PerformDependentDiagnostics(Pattern, TemplateArgs); + // Instantiate any out-of-line class template partial // specializations now. for (TemplateDeclInstantiator::delayed_partial_spec_iterator diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 15ddd7df98e..bdbe71dd8ab 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -935,8 +935,6 @@ TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { if (!Instantiated) return 0; - Instantiated->setAccess(D->getAccess()); - // Link the instantiated function template declaration to the function // template from which it was instantiated. FunctionTemplateDecl *InstTemplate @@ -954,8 +952,12 @@ TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { InstTemplate->setInstantiatedFromMemberTemplate(D); // Make declarations visible in the appropriate context. - if (!isFriend) + if (!isFriend) { Owner->addDecl(InstTemplate); + } else if (InstTemplate->getDeclContext()->isRecord() && + !D->getPreviousDecl()) { + SemaRef.CheckFriendAccess(InstTemplate); + } return InstTemplate; } @@ -1526,7 +1528,15 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, if (D->isPure()) SemaRef.CheckPureMethod(Method, SourceRange()); - Method->setAccess(D->getAccess()); + // Propagate access. For a non-friend declaration, the access is + // whatever we're propagating from. For a friend, it should be the + // previous declaration we just found. + if (isFriend && Method->getPreviousDecl()) + Method->setAccess(Method->getPreviousDecl()->getAccess()); + else + Method->setAccess(D->getAccess()); + if (FunctionTemplate) + FunctionTemplate->setAccess(Method->getAccess()); SemaRef.CheckOverrideControl(Method); @@ -1536,18 +1546,28 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, if (D->isDeletedAsWritten()) Method->setDeletedAsWritten(); + // If there's a function template, let our caller handle it. if (FunctionTemplate) { - // If there's a function template, let our caller handle it. + // do nothing + + // Don't hide a (potentially) valid declaration with an invalid one. } else if (Method->isInvalidDecl() && !Previous.empty()) { - // Don't hide a (potentially) valid declaration with an invalid one. - } else { - NamedDecl *DeclToAdd = (TemplateParams - ? cast<NamedDecl>(FunctionTemplate) - : Method); - if (isFriend) - Record->makeDeclVisibleInContext(DeclToAdd); - else if (!IsClassScopeSpecialization) - Owner->addDecl(DeclToAdd); + // do nothing + + // Otherwise, check access to friends and make them visible. + } else if (isFriend) { + // We only need to re-check access for methods which we didn't + // manage to match during parsing. + if (!D->getPreviousDecl()) + SemaRef.CheckFriendAccess(Method); + + Record->makeDeclVisibleInContext(Method); + + // Otherwise, add the declaration. We don't need to do this for + // class-scope specializations because we'll have matched them with + // the appropriate template. + } else if (!IsClassScopeSpecialization) { + Owner->addDecl(Method); } if (D->isExplicitlyDefaulted()) { |