зеркало из https://github.com/microsoft/clang-1.git
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:
Родитель
d2bf0cdca4
Коммит
c373d48502
|
@ -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}}
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче