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
This commit is contained in:
John McCall 2010-01-27 01:50:18 +00:00
Родитель d2bf0cdca4
Коммит c373d48502
11 изменённых файлов: 276 добавлений и 105 удалений

Просмотреть файл

@ -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; }

Просмотреть файл

@ -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();

Просмотреть файл

@ -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<RecordType>();
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<PointerType>();
assert(PT && "base of arrow member access is not pointer");
BaseType = PT->getPointeeType();
}
RT = BaseType->getAs<RecordType>();
assert(RT && "base of member expression does not name record");
}
return cast<CXXRecordDecl>(RT->getDecl());
}
Stmt::child_iterator UnresolvedMemberExpr::child_begin() {
return child_iterator(&Base);
}

Просмотреть файл

@ -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(

Просмотреть файл

@ -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)

Просмотреть файл

@ -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:

Просмотреть файл

@ -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);
}

Просмотреть файл

@ -4851,6 +4851,14 @@ Sema::PrintOverloadCandidates(OverloadCandidateSet& CandidateSet,
}
}
static bool CheckUnresolvedAccess(Sema &S, Expr *E, NamedDecl *D,
AccessSpecifier AS) {
if (isa<UnresolvedLookupExpr>(E))
return S.CheckUnresolvedLookupAccess(cast<UnresolvedLookupExpr>(E), D, AS);
return S.CheckUnresolvedMemberAccess(cast<UnresolvedMemberExpr>(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<FunctionDecl *, 4> 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<FunctionDecl>(Specialization->getCanonicalDecl()));
Matches.addDecl(cast<FunctionDecl>(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<FunctionDecl>(FunDecl->getCanonicalDecl()));
Matches.addDecl(cast<FunctionDecl>(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<FunctionDecl>(*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<FunctionDecl *, 4>::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<FunctionDecl *, 8> 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<FunctionDecl>(*Result);
}
// [...] any function template specializations in the set are
// eliminated if the set also contains a non-template function, [...]
llvm::SmallVector<FunctionDecl *, 4> 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<FunctionDecl>(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<FunctionDecl>(*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<FunctionDecl>(*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<CXXMethodDecl>(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<CXXMethodDecl>(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<CXXMethodDecl>(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<CXXMethodDecl>(Best->Function);
CheckUnresolvedMemberAccess(UnresExpr, Method, Best->getAccess());
break;
case OR_No_Viable_Function:

Просмотреть файл

@ -1525,17 +1525,19 @@ Sema::OwningExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
Qualifier = static_cast<NestedNameSpecifier*>(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<FunctionDecl *, 8> 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<FunctionDecl>(*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<FunctionDecl *, 8> 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<FunctionDecl>(*Result);
if (Specialization->getTemplateSpecializationKind() == TSK_Undeclared) {
Diag(D.getIdentifierLoc(),

Просмотреть файл

@ -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<FunctionDecl>(*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<FunctionDecl>(*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<FunctionDecl>(*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<FunctionDecl>(*I)->getPrimaryTemplate()->getTemplateParameters(),
*cast<FunctionDecl>(*I)->getTemplateSpecializationArgs());
return 0;
return SpecEnd;
}
/// \brief Returns the more specialized class template partial specialization

Просмотреть файл

@ -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}}
}
}