aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn McCall <rjmccall@apple.com>2010-01-27 01:50:18 +0000
committerJohn McCall <rjmccall@apple.com>2010-01-27 01:50:18 +0000
commitc373d48502ca7683ab55385f5bd624d778eb288d (patch)
tree0de412804faa62614dc3ee788df2b4e95c80a8c8
parentd2bf0cdca441216b0ae7791a59516beac403682d (diff)
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
-rw-r--r--include/clang/AST/ExprCXX.h33
-rw-r--r--include/clang/AST/UnresolvedSet.h5
-rw-r--r--lib/AST/ExprCXX.cpp33
-rw-r--r--lib/Sema/Sema.h24
-rw-r--r--lib/Sema/SemaAccess.cpp42
-rw-r--r--lib/Sema/SemaDecl.cpp1
-rw-r--r--lib/Sema/SemaExpr.cpp17
-rw-r--r--lib/Sema/SemaOverload.cpp84
-rw-r--r--lib/Sema/SemaTemplate.cpp40
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp69
-rw-r--r--test/CXX/class.access/p4.cpp33
11 files changed, 276 insertions, 105 deletions
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<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);
}
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<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:
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<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(),
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<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
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}}
+ }
+}