From: John McCall Date: Wed, 27 Jan 2010 01:50:18 +0000 (+0000) Subject: Implement access control for overloaded functions. Suppress access control X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c373d48502ca7683ab55385f5bd624d778eb288d;p=clang Implement access control for overloaded functions. Suppress access control diagnostics in "early" lookups, such as during typename checks and when building unresolved lookup expressions. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@94647 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index ad3f4b1c91..9dd3bc96ef 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -1077,6 +1077,13 @@ class UnresolvedLookupExpr : public Expr { /// The name declared. DeclarationName Name; + /// The naming class (C++ [class.access.base]p5) of the lookup, if + /// any. This can generally be recalculated from the context chain, + /// but that can be fairly expensive for unqualified lookups. If we + /// want to improve memory use here, this could go in a union + /// against the qualified-lookup bits. + CXXRecordDecl *NamingClass; + /// The qualifier given, if any. NestedNameSpecifier *Qualifier; @@ -1099,12 +1106,13 @@ class UnresolvedLookupExpr : public Expr { /// This requires all the results to be function templates. bool HasExplicitTemplateArgs; - UnresolvedLookupExpr(QualType T, bool Dependent, + UnresolvedLookupExpr(QualType T, bool Dependent, CXXRecordDecl *NamingClass, NestedNameSpecifier *Qualifier, SourceRange QRange, DeclarationName Name, SourceLocation NameLoc, bool RequiresADL, bool Overloaded, bool HasTemplateArgs) : Expr(UnresolvedLookupExprClass, T, Dependent, Dependent), - Name(Name), Qualifier(Qualifier), QualifierRange(QRange), + Name(Name), NamingClass(NamingClass), + Qualifier(Qualifier), QualifierRange(QRange), NameLoc(NameLoc), RequiresADL(RequiresADL), Overloaded(Overloaded), HasExplicitTemplateArgs(HasTemplateArgs) {} @@ -1112,18 +1120,21 @@ class UnresolvedLookupExpr : public Expr { public: static UnresolvedLookupExpr *Create(ASTContext &C, bool Dependent, + CXXRecordDecl *NamingClass, NestedNameSpecifier *Qualifier, SourceRange QualifierRange, DeclarationName Name, SourceLocation NameLoc, bool ADL, bool Overloaded) { return new(C) UnresolvedLookupExpr(Dependent ? C.DependentTy : C.OverloadTy, - Dependent, Qualifier, QualifierRange, + Dependent, NamingClass, + Qualifier, QualifierRange, Name, NameLoc, ADL, Overloaded, false); } static UnresolvedLookupExpr *Create(ASTContext &C, bool Dependent, + CXXRecordDecl *NamingClass, NestedNameSpecifier *Qualifier, SourceRange QualifierRange, DeclarationName Name, @@ -1141,10 +1152,6 @@ public: Results.append(Begin, End); } - void addDecl(NamedDecl *Decl) { - Results.addDecl(Decl); - } - typedef UnresolvedSetImpl::iterator decls_iterator; decls_iterator decls_begin() const { return Results.begin(); } decls_iterator decls_end() const { return Results.end(); } @@ -1165,6 +1172,11 @@ public: /// Gets the location of the name. SourceLocation getNameLoc() const { return NameLoc; } + /// Gets the 'naming class' (in the sense of C++0x + /// [class.access.base]p5) of the lookup. This is the scope + /// that was looked in to find these results. + CXXRecordDecl *getNamingClass() const { return NamingClass; } + /// Fetches the nested-name qualifier, if one was given. NestedNameSpecifier *getQualifier() const { return Qualifier; } @@ -1798,8 +1810,8 @@ public: /// Adds a declaration to the unresolved set. By assumption, all of /// these happen at initialization time and properties like /// 'Dependent' and 'HasUnresolvedUsing' take them into account. - void addDecl(NamedDecl *Decl) { - Results.addDecl(Decl); + void addDecls(UnresolvedSetIterator Begin, UnresolvedSetIterator End) { + Results.append(Begin, End); } typedef UnresolvedSetImpl::iterator decls_iterator; @@ -1843,6 +1855,9 @@ public: /// that qualifies the member name. SourceRange getQualifierRange() const { return QualifierRange; } + /// \brief Retrieves the naming class of this lookup. + CXXRecordDecl *getNamingClass() const; + /// \brief Retrieve the name of the member that this expression /// refers to. DeclarationName getMemberName() const { return MemberName; } diff --git a/include/clang/AST/UnresolvedSet.h b/include/clang/AST/UnresolvedSet.h index 055d152646..d2e33edf08 100644 --- a/include/clang/AST/UnresolvedSet.h +++ b/include/clang/AST/UnresolvedSet.h @@ -137,6 +137,11 @@ public: *I.ir = DeclEntry(New, AS); } + void erase(unsigned I) { + decls()[I] = decls().back(); + decls().pop_back(); + } + void erase(iterator I) { *I.ir = decls().back(); decls().pop_back(); diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index a6574efda8..475dcf2048 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -116,6 +116,7 @@ Stmt::child_iterator CXXPseudoDestructorExpr::child_end() { // UnresolvedLookupExpr UnresolvedLookupExpr * UnresolvedLookupExpr::Create(ASTContext &C, bool Dependent, + CXXRecordDecl *NamingClass, NestedNameSpecifier *Qualifier, SourceRange QualifierRange, DeclarationName Name, SourceLocation NameLoc, bool ADL, @@ -125,7 +126,8 @@ UnresolvedLookupExpr::Create(ASTContext &C, bool Dependent, ExplicitTemplateArgumentList::sizeFor(Args)); UnresolvedLookupExpr *ULE = new (Mem) UnresolvedLookupExpr(Dependent ? C.DependentTy : C.OverloadTy, - Dependent, Qualifier, QualifierRange, + Dependent, NamingClass, + Qualifier, QualifierRange, Name, NameLoc, ADL, /*Overload*/ true, /*ExplicitTemplateArgs*/ true); @@ -651,6 +653,35 @@ UnresolvedMemberExpr::Create(ASTContext &C, bool Dependent, Member, MemberLoc, TemplateArgs); } +CXXRecordDecl *UnresolvedMemberExpr::getNamingClass() const { + // Unlike for UnresolvedLookupExpr, it is very easy to re-derive this. + + // If there was a nested name specifier, it names the naming class. + // It can't be dependent: after all, we were actually able to do the + // lookup. + const RecordType *RT; + if (Qualifier) { + Type *T = Qualifier->getAsType(); + assert(T && "qualifier in member expression does not name type"); + RT = T->getAs(); + assert(RT && "qualifier in member expression does not name record"); + + // Otherwise the naming class must have been the base class. + } else { + QualType BaseType = getBaseType().getNonReferenceType(); + if (isArrow()) { + const PointerType *PT = BaseType->getAs(); + assert(PT && "base of arrow member access is not pointer"); + BaseType = PT->getPointeeType(); + } + + RT = BaseType->getAs(); + assert(RT && "base of member expression does not name record"); + } + + return cast(RT->getDecl()); +} + Stmt::child_iterator UnresolvedMemberExpr::child_begin() { return child_iterator(&Base); } diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index d041f54a02..86d867858b 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -60,6 +60,7 @@ namespace clang { class CallExpr; class DeclRefExpr; class UnresolvedLookupExpr; + class UnresolvedMemberExpr; class VarDecl; class ParmVarDecl; class TypedefDecl; @@ -2376,8 +2377,14 @@ public: CXXBasePaths &Paths, bool NoPrivileges = false); - void CheckAccess(const LookupResult &R); + bool CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E, + NamedDecl *D, + AccessSpecifier Access); + bool CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E, + NamedDecl *D, + AccessSpecifier Access); bool CheckAccess(const LookupResult &R, NamedDecl *D, AccessSpecifier Access); + void CheckAccess(const LookupResult &R); bool CheckBaseClassAccess(QualType Derived, QualType Base, unsigned InaccessibleBaseID, @@ -2882,14 +2889,13 @@ public: FunctionTemplateDecl *getMoreSpecializedTemplate(FunctionTemplateDecl *FT1, FunctionTemplateDecl *FT2, TemplatePartialOrderingContext TPOC); - FunctionDecl *getMostSpecialized(FunctionDecl **Specializations, - unsigned NumSpecializations, - TemplatePartialOrderingContext TPOC, - SourceLocation Loc, - const PartialDiagnostic &NoneDiag, - const PartialDiagnostic &AmbigDiag, - const PartialDiagnostic &CandidateDiag, - unsigned *Index = 0); + UnresolvedSetIterator getMostSpecialized(UnresolvedSetIterator SBegin, + UnresolvedSetIterator SEnd, + TemplatePartialOrderingContext TPOC, + SourceLocation Loc, + const PartialDiagnostic &NoneDiag, + const PartialDiagnostic &AmbigDiag, + const PartialDiagnostic &CandidateDiag); ClassTemplatePartialSpecializationDecl * getMoreSpecializedPartialSpecialization( diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp index 51f9e300ef..26bafa525d 100644 --- a/lib/Sema/SemaAccess.cpp +++ b/lib/Sema/SemaAccess.cpp @@ -16,6 +16,8 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/ExprCXX.h" + using namespace clang; /// SetMemberAccessSpecifier - Set the access specifier of a member. @@ -231,6 +233,46 @@ bool Sema::CheckAccess(const LookupResult &R, NamedDecl *D, return true; } +bool Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E, + NamedDecl *D, AccessSpecifier Access) { + if (!getLangOptions().AccessControl || !E->getNamingClass()) + return false; + + // Fake up a lookup result. + LookupResult R(*this, E->getName(), E->getNameLoc(), LookupOrdinaryName); + R.suppressDiagnostics(); + + R.setNamingClass(E->getNamingClass()); + R.addDecl(D, Access); + + // FIXME: protected check (triggers for member-address expressions) + + return CheckAccess(R, D, Access); +} + +/// Perform access-control checking on a previously-unresolved member +/// access which has now been resolved to a member. +bool Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E, + NamedDecl *D, AccessSpecifier Access) { + if (!getLangOptions().AccessControl) + return false; + + // Fake up a lookup result. + LookupResult R(*this, E->getMemberName(), E->getMemberLoc(), + LookupOrdinaryName); + R.suppressDiagnostics(); + + R.setNamingClass(E->getNamingClass()); + R.addDecl(D, Access); + + if (CheckAccess(R, D, Access)) + return true; + + // FIXME: protected check + + return false; +} + /// Checks access to all the declarations in the given result set. void Sema::CheckAccess(const LookupResult &R) { for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 876fcb32ba..398c156f9b 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -135,6 +135,7 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, case LookupResult::NotFoundInCurrentInstantiation: case LookupResult::FoundOverloaded: case LookupResult::FoundUnresolvedValue: + Result.suppressDiagnostics(); return 0; case LookupResult::Ambiguous: diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 1d0374dcbb..5be017a754 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -1497,16 +1497,20 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, CheckDeclInExpr(*this, R.getNameLoc(), R.getFoundDecl())) return ExprError(); + // Otherwise, just build an unresolved lookup expression. Suppress + // any lookup-related diagnostics; we'll hash these out later, when + // we've picked a target. + R.suppressDiagnostics(); + bool Dependent = UnresolvedLookupExpr::ComputeDependence(R.begin(), R.end(), 0); UnresolvedLookupExpr *ULE - = UnresolvedLookupExpr::Create(Context, Dependent, + = UnresolvedLookupExpr::Create(Context, Dependent, R.getNamingClass(), (NestedNameSpecifier*) SS.getScopeRep(), SS.getRange(), R.getLookupName(), R.getNameLoc(), NeedsADL, R.isOverloadedResult()); - for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) - ULE->addDecl(*I); + ULE->addDecls(R.begin(), R.end()); return Owned(ULE); } @@ -2544,6 +2548,10 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType, R.isUnresolvableResult() || UnresolvedLookupExpr::ComputeDependence(R.begin(), R.end(), TemplateArgs); + // Suppress any lookup-related diagnostics; we'll do these when we + // pick a member. + R.suppressDiagnostics(); + UnresolvedMemberExpr *MemExpr = UnresolvedMemberExpr::Create(Context, Dependent, R.isUnresolvableResult(), @@ -2552,8 +2560,7 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType, Qualifier, SS.getRange(), MemberName, MemberLoc, TemplateArgs); - for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) - MemExpr->addDecl(*I); + MemExpr->addDecls(R.begin(), R.end()); return Owned(MemExpr); } diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 47a7d17519..f2f24ea59a 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -4851,6 +4851,14 @@ Sema::PrintOverloadCandidates(OverloadCandidateSet& CandidateSet, } } +static bool CheckUnresolvedAccess(Sema &S, Expr *E, NamedDecl *D, + AccessSpecifier AS) { + if (isa(E)) + return S.CheckUnresolvedLookupAccess(cast(E), D, AS); + + return S.CheckUnresolvedMemberAccess(cast(E), D, AS); +} + /// ResolveAddressOfOverloadedFunction - Try to resolve the address of /// an overloaded function (C++ [over.over]), where @p From is an /// expression with overloaded function type and @p ToType is the type @@ -4928,7 +4936,7 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, // Look through all of the overloaded functions, searching for one // whose type matches exactly. - llvm::SmallPtrSet Matches; + UnresolvedSet<4> Matches; // contains only FunctionDecls bool FoundNonTemplateFunction = false; for (UnresolvedSetIterator I = Fns->begin(), E = Fns->end(); I != E; ++I) { // Look through any using declarations to find the underlying function. @@ -4972,8 +4980,8 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, // a candidate? Find a testcase before changing the code. assert(FunctionType == Context.getCanonicalType(Specialization->getType())); - Matches.insert( - cast(Specialization->getCanonicalDecl())); + Matches.addDecl(cast(Specialization->getCanonicalDecl()), + I.getAccess()); } continue; @@ -4996,7 +5004,8 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, if (Context.hasSameUnqualifiedType(FunctionType, FunDecl->getType()) || IsNoReturnConversion(Context, FunDecl->getType(), FunctionType, ResultTy)) { - Matches.insert(cast(FunDecl->getCanonicalDecl())); + Matches.addDecl(cast(FunDecl->getCanonicalDecl()), + I.getAccess()); FoundNonTemplateFunction = true; } } @@ -5006,14 +5015,15 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, if (Matches.empty()) return 0; else if (Matches.size() == 1) { - FunctionDecl *Result = *Matches.begin(); + FunctionDecl *Result = cast(*Matches.begin()); MarkDeclarationReferenced(From->getLocStart(), Result); + if (Complain) + CheckUnresolvedAccess(*this, OvlExpr, Result, Matches.begin().getAccess()); return Result; } // C++ [over.over]p4: // If more than one function is selected, [...] - typedef llvm::SmallPtrSet::iterator MatchIter; if (!FoundNonTemplateFunction) { // [...] and any given function template specialization F1 is // eliminated if the set contains a second function template @@ -5025,41 +5035,50 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, // two-pass algorithm (similar to the one used to identify the // best viable function in an overload set) that identifies the // best function template (if it exists). - llvm::SmallVector TemplateMatches(Matches.begin(), - Matches.end()); - FunctionDecl *Result = - getMostSpecialized(TemplateMatches.data(), TemplateMatches.size(), + + UnresolvedSetIterator Result = + getMostSpecialized(Matches.begin(), Matches.end(), TPOC_Other, From->getLocStart(), PDiag(), PDiag(diag::err_addr_ovl_ambiguous) - << TemplateMatches[0]->getDeclName(), + << Matches[0]->getDeclName(), PDiag(diag::note_ovl_candidate) << (unsigned) oc_function_template); - MarkDeclarationReferenced(From->getLocStart(), Result); - return Result; + assert(Result != Matches.end() && "no most-specialized template"); + MarkDeclarationReferenced(From->getLocStart(), *Result); + if (Complain) + CheckUnresolvedAccess(*this, OvlExpr, *Result, Result.getAccess()); + return cast(*Result); } // [...] any function template specializations in the set are // eliminated if the set also contains a non-template function, [...] - llvm::SmallVector RemainingMatches; - for (MatchIter M = Matches.begin(), MEnd = Matches.end(); M != MEnd; ++M) - if ((*M)->getPrimaryTemplate() == 0) - RemainingMatches.push_back(*M); + for (unsigned I = 0, N = Matches.size(); I != N; ) { + if (cast(Matches[I].getDecl())->getPrimaryTemplate() == 0) + ++I; + else { + Matches.erase(I); + --N; + } + } // [...] After such eliminations, if any, there shall remain exactly one // selected function. - if (RemainingMatches.size() == 1) { - FunctionDecl *Result = RemainingMatches.front(); - MarkDeclarationReferenced(From->getLocStart(), Result); - return Result; + if (Matches.size() == 1) { + UnresolvedSetIterator Match = Matches.begin(); + MarkDeclarationReferenced(From->getLocStart(), *Match); + if (Complain) + CheckUnresolvedAccess(*this, OvlExpr, *Match, Match.getAccess()); + return cast(*Match); } // FIXME: We should probably return the same thing that BestViableFunction // returns (even if we issue the diagnostics here). Diag(From->getLocStart(), diag::err_addr_ovl_ambiguous) - << RemainingMatches[0]->getDeclName(); - for (unsigned I = 0, N = RemainingMatches.size(); I != N; ++I) - NoteOverloadCandidate(RemainingMatches[I]); + << Matches[0]->getDeclName(); + for (UnresolvedSetIterator I = Matches.begin(), + E = Matches.end(); I != E; ++I) + NoteOverloadCandidate(cast(*I)); return 0; } @@ -5345,6 +5364,7 @@ Sema::BuildOverloadedCallExpr(Expr *Fn, UnresolvedLookupExpr *ULE, switch (BestViableFunction(CandidateSet, Fn->getLocStart(), Best)) { case OR_Success: { FunctionDecl *FDecl = Best->Function; + CheckUnresolvedLookupAccess(ULE, FDecl, Best->getAccess()); Fn = FixOverloadedFunctionReference(Fn, FDecl); return BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, NumArgs, RParenLoc); } @@ -5425,8 +5445,9 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, } if (Input->isTypeDependent()) { + CXXRecordDecl *NamingClass = 0; // because lookup ignores member operators UnresolvedLookupExpr *Fn - = UnresolvedLookupExpr::Create(Context, /*Dependent*/ true, + = UnresolvedLookupExpr::Create(Context, /*Dependent*/ true, NamingClass, 0, SourceRange(), OpName, OpLoc, /*ADL*/ true, IsOverloaded(Fns)); Fn->addDecls(Fns.begin(), Fns.end()); @@ -5467,6 +5488,8 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, // We matched an overloaded operator. Build a call to that // operator. + // FIXME: access control + // Convert the arguments. if (CXXMethodDecl *Method = dyn_cast(FnDecl)) { if (PerformObjectArgumentInitialization(Input, Method)) @@ -5592,8 +5615,9 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, } // FIXME: save results of ADL from here? + CXXRecordDecl *NamingClass = 0; // because lookup ignores member operators UnresolvedLookupExpr *Fn - = UnresolvedLookupExpr::Create(Context, /*Dependent*/ true, + = UnresolvedLookupExpr::Create(Context, /*Dependent*/ true, NamingClass, 0, SourceRange(), OpName, OpLoc, /*ADL*/ true, IsOverloaded(Fns)); @@ -5647,6 +5671,8 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, // We matched an overloaded operator. Build a call to that // operator. + // FIXME: access control + // Convert the arguments. if (CXXMethodDecl *Method = dyn_cast(FnDecl)) { OwningExprResult Arg1 @@ -5783,8 +5809,9 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, // expression. if (Args[0]->isTypeDependent() || Args[1]->isTypeDependent()) { + CXXRecordDecl *NamingClass = 0; // because lookup ignores member operators UnresolvedLookupExpr *Fn - = UnresolvedLookupExpr::Create(Context, /*Dependent*/ true, + = UnresolvedLookupExpr::Create(Context, /*Dependent*/ true, NamingClass, 0, SourceRange(), OpName, LLoc, /*ADL*/ true, /*Overloaded*/ false); // Can't add any actual overloads yet @@ -5819,6 +5846,8 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, // We matched an overloaded operator. Build a call to that // operator. + // FIXME: access control + // Convert the arguments. CXXMethodDecl *Method = cast(FnDecl); if (PerformObjectArgumentInitialization(Args[0], Method) || @@ -5968,6 +5997,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, switch (BestViableFunction(CandidateSet, UnresExpr->getLocStart(), Best)) { case OR_Success: Method = cast(Best->Function); + CheckUnresolvedMemberAccess(UnresExpr, Method, Best->getAccess()); break; case OR_No_Viable_Function: diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 00401560c6..f660b3c2ee 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -1525,17 +1525,19 @@ Sema::OwningExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS, Qualifier = static_cast(SS.getScopeRep()); QualifierRange = SS.getRange(); } + + // We don't want lookup warnings at this point. + R.suppressDiagnostics(); bool Dependent = UnresolvedLookupExpr::ComputeDependence(R.begin(), R.end(), &TemplateArgs); UnresolvedLookupExpr *ULE - = UnresolvedLookupExpr::Create(Context, Dependent, + = UnresolvedLookupExpr::Create(Context, Dependent, R.getNamingClass(), Qualifier, QualifierRange, R.getLookupName(), R.getNameLoc(), RequiresADL, TemplateArgs); - for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) - ULE->addDecl(*I); + ULE->addDecls(R.begin(), R.end()); return Owned(ULE); } @@ -3817,8 +3819,7 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, LookupResult &Previous) { // The set of function template specializations that could match this // explicit function template specialization. - typedef llvm::SmallVector CandidateSet; - CandidateSet Candidates; + UnresolvedSet<8> Candidates; DeclContext *FDLookupContext = FD->getDeclContext()->getLookupContext(); for (LookupResult::iterator I = Previous.begin(), E = Previous.end(); @@ -3851,22 +3852,24 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, } // Record this candidate. - Candidates.push_back(Specialization); + Candidates.addDecl(Specialization, I.getAccess()); } } // Find the most specialized function template. - FunctionDecl *Specialization = getMostSpecialized(Candidates.data(), - Candidates.size(), - TPOC_Other, - FD->getLocation(), + UnresolvedSetIterator Result + = getMostSpecialized(Candidates.begin(), Candidates.end(), + TPOC_Other, FD->getLocation(), PartialDiagnostic(diag::err_function_template_spec_no_match) << FD->getDeclName(), PartialDiagnostic(diag::err_function_template_spec_ambiguous) << FD->getDeclName() << (ExplicitTemplateArgs != 0), PartialDiagnostic(diag::note_function_template_spec_matched)); - if (!Specialization) + if (Result == Candidates.end()) return true; + + // Ignore access information; it doesn't figure into redeclaration checking. + FunctionDecl *Specialization = cast(*Result); // FIXME: Check if the prior specialization has a point of instantiation. // If so, we have run afoul of . @@ -4568,7 +4571,7 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, // A member function [...] of a class template can be explicitly // instantiated from the member definition associated with its class // template. - llvm::SmallVector Matches; + UnresolvedSet<8> Matches; for (LookupResult::iterator P = Previous.begin(), PEnd = Previous.end(); P != PEnd; ++P) { NamedDecl *Prev = *P; @@ -4577,7 +4580,7 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, if (Context.hasSameUnqualifiedType(Method->getType(), R)) { Matches.clear(); - Matches.push_back(Method); + Matches.addDecl(Method, P.getAccess()); if (Method->getTemplateSpecializationKind() == TSK_Undeclared) break; } @@ -4599,19 +4602,22 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, continue; } - Matches.push_back(Specialization); + Matches.addDecl(Specialization, P.getAccess()); } // Find the most specialized function template specialization. - FunctionDecl *Specialization - = getMostSpecialized(Matches.data(), Matches.size(), TPOC_Other, + UnresolvedSetIterator Result + = getMostSpecialized(Matches.begin(), Matches.end(), TPOC_Other, D.getIdentifierLoc(), PartialDiagnostic(diag::err_explicit_instantiation_not_known) << Name, PartialDiagnostic(diag::err_explicit_instantiation_ambiguous) << Name, PartialDiagnostic(diag::note_explicit_instantiation_candidate)); - if (!Specialization) + if (Result == Matches.end()) return true; + + // Ignore access control bits, we don't need them for redeclaration checking. + FunctionDecl *Specialization = cast(*Result); if (Specialization->getTemplateSpecializationKind() == TSK_Undeclared) { Diag(D.getIdentifierLoc(), diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 7b433e901e..b9160930cb 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -1987,11 +1987,11 @@ static bool isSameTemplate(TemplateDecl *T1, TemplateDecl *T2) { /// \brief Retrieve the most specialized of the given function template /// specializations. /// -/// \param Specializations the set of function template specializations that -/// we will be comparing. +/// \param SpecBegin the start iterator of the function template +/// specializations that we will be comparing. /// -/// \param NumSpecializations the number of function template specializations in -/// \p Specializations +/// \param SpecEnd the end iterator of the function template +/// specializations, paired with \p SpecBegin. /// /// \param TPOC the partial ordering context to use to compare the function /// template specializations. @@ -2015,41 +2015,37 @@ static bool isSameTemplate(TemplateDecl *T1, TemplateDecl *T2) { /// specialization. /// /// \returns the most specialized function template specialization, if -/// found. Otherwise, returns NULL. +/// found. Otherwise, returns SpecEnd. /// /// \todo FIXME: Consider passing in the "also-ran" candidates that failed /// template argument deduction. -FunctionDecl *Sema::getMostSpecialized(FunctionDecl **Specializations, - unsigned NumSpecializations, - TemplatePartialOrderingContext TPOC, - SourceLocation Loc, - const PartialDiagnostic &NoneDiag, - const PartialDiagnostic &AmbigDiag, - const PartialDiagnostic &CandidateDiag, - unsigned *Index) { - if (NumSpecializations == 0) { +UnresolvedSetIterator +Sema::getMostSpecialized(UnresolvedSetIterator SpecBegin, + UnresolvedSetIterator SpecEnd, + TemplatePartialOrderingContext TPOC, + SourceLocation Loc, + const PartialDiagnostic &NoneDiag, + const PartialDiagnostic &AmbigDiag, + const PartialDiagnostic &CandidateDiag) { + if (SpecBegin == SpecEnd) { Diag(Loc, NoneDiag); - return 0; + return SpecEnd; } - if (NumSpecializations == 1) { - if (Index) - *Index = 0; - - return Specializations[0]; - } - + if (SpecBegin + 1 == SpecEnd) + return SpecBegin; // Find the function template that is better than all of the templates it // has been compared to. - unsigned Best = 0; + UnresolvedSetIterator Best = SpecBegin; FunctionTemplateDecl *BestTemplate - = Specializations[Best]->getPrimaryTemplate(); + = cast(*Best)->getPrimaryTemplate(); assert(BestTemplate && "Not a function template specialization?"); - for (unsigned I = 1; I != NumSpecializations; ++I) { - FunctionTemplateDecl *Challenger = Specializations[I]->getPrimaryTemplate(); + for (UnresolvedSetIterator I = SpecBegin + 1; I != SpecEnd; ++I) { + FunctionTemplateDecl *Challenger + = cast(*I)->getPrimaryTemplate(); assert(Challenger && "Not a function template specialization?"); - if (isSameTemplate(getMoreSpecializedTemplate(BestTemplate, Challenger, + if (isSameTemplate(getMoreSpecializedTemplate(BestTemplate, Challenger, TPOC), Challenger)) { Best = I; @@ -2060,8 +2056,9 @@ FunctionDecl *Sema::getMostSpecialized(FunctionDecl **Specializations, // Make sure that the "best" function template is more specialized than all // of the others. bool Ambiguous = false; - for (unsigned I = 0; I != NumSpecializations; ++I) { - FunctionTemplateDecl *Challenger = Specializations[I]->getPrimaryTemplate(); + for (UnresolvedSetIterator I = SpecBegin; I != SpecEnd; ++I) { + FunctionTemplateDecl *Challenger + = cast(*I)->getPrimaryTemplate(); if (I != Best && !isSameTemplate(getMoreSpecializedTemplate(BestTemplate, Challenger, TPOC), @@ -2073,22 +2070,20 @@ FunctionDecl *Sema::getMostSpecialized(FunctionDecl **Specializations, if (!Ambiguous) { // We found an answer. Return it. - if (Index) - *Index = Best; - return Specializations[Best]; + return Best; } // Diagnose the ambiguity. Diag(Loc, AmbigDiag); // FIXME: Can we order the candidates in some sane way? - for (unsigned I = 0; I != NumSpecializations; ++I) - Diag(Specializations[I]->getLocation(), CandidateDiag) + for (UnresolvedSetIterator I = SpecBegin; I != SpecEnd; ++I) + Diag((*I)->getLocation(), CandidateDiag) << getTemplateArgumentBindingsText( - Specializations[I]->getPrimaryTemplate()->getTemplateParameters(), - *Specializations[I]->getTemplateSpecializationArgs()); + cast(*I)->getPrimaryTemplate()->getTemplateParameters(), + *cast(*I)->getTemplateSpecializationArgs()); - return 0; + return SpecEnd; } /// \brief Returns the more specialized class template partial specialization diff --git a/test/CXX/class.access/p4.cpp b/test/CXX/class.access/p4.cpp new file mode 100644 index 0000000000..7d89659901 --- /dev/null +++ b/test/CXX/class.access/p4.cpp @@ -0,0 +1,33 @@ +// RUN: %clang_cc1 -fsyntax-only -faccess-control -verify %s + +// C++0x [class.access]p4: + +// Access control is applied uniformly to all names, whether the +// names are referred to from declarations or expressions. In the +// case of overloaded function names, access control is applied to +// the function selected by overload resolution. + +class Public {} PublicInst; +class Protected {} ProtectedInst; +class Private {} PrivateInst; + +namespace test0 { + class A { + public: + void foo(Public&); + protected: + void foo(Protected&); // expected-note 2 {{declared protected here}} + private: + void foo(Private&); // expected-note 2 {{declared private here}} + }; + + void test(A *op) { + op->foo(PublicInst); + op->foo(ProtectedInst); // expected-error {{access to protected member outside any class}} + op->foo(PrivateInst); // expected-error {{access to private member outside any class}} + + void (A::*a)(Public&) = &A::foo; + void (A::*b)(Protected&) = &A::foo; // expected-error {{access to protected member outside any class}} + void (A::*c)(Private&) = &A::foo; // expected-error {{access to private member outside any class}} + } +}