From 6e26689f5d513e24ad7783a4493201930fdeccc0 Mon Sep 17 00:00:00 2001 From: John McCall Date: Tue, 26 Jan 2010 03:27:55 +0000 Subject: [PATCH] Preserve access bits through overload resolution much better. Some general refactoring in operator resolution. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@94498 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/ExprCXX.h | 4 ++ lib/Sema/Lookup.h | 4 ++ lib/Sema/Sema.h | 20 +++++--- lib/Sema/SemaExpr.cpp | 27 +++-------- lib/Sema/SemaLookup.cpp | 28 +++++------ lib/Sema/SemaOverload.cpp | 97 +++++++++++++++++-------------------- lib/Sema/TreeTransform.h | 13 ++--- 7 files changed, 90 insertions(+), 103 deletions(-) diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index 6ce95ac522..2b20b52b60 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -1137,6 +1137,10 @@ public: UnresolvedSetImpl::const_iterator End, const TemplateArgumentListInfo *Args); + void addDecls(UnresolvedSetIterator Begin, UnresolvedSetIterator End) { + Results.append(Begin, End); + } + void addDecl(NamedDecl *Decl) { Results.addDecl(Decl); } diff --git a/lib/Sema/Lookup.h b/lib/Sema/Lookup.h index f4cea2e88a..0c0f363cbd 100644 --- a/lib/Sema/Lookup.h +++ b/lib/Sema/Lookup.h @@ -224,6 +224,10 @@ public: return Ambiguity; } + const UnresolvedSetImpl &asUnresolvedSet() const { + return Decls; + } + iterator begin() const { return iterator(Decls.begin()); } iterator end() const { return iterator(Decls.end()); } diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 6e0993a715..42dac8fafc 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -950,10 +950,15 @@ public: // Members have to be NamespaceDecl* or TranslationUnitDecl*. // TODO: make this is a typesafe union. typedef llvm::SmallPtrSet AssociatedNamespaceSet; - - typedef llvm::SmallPtrSet FunctionSet; + // Members have to be a function or function template. + typedef llvm::SmallPtrSet ADLFunctionSet; typedef llvm::SmallPtrSet AssociatedClassSet; + void AddOverloadCandidate(NamedDecl *Function, + AccessSpecifier Access, + Expr **Args, unsigned NumArgs, + OverloadCandidateSet &CandidateSet); + void AddOverloadCandidate(FunctionDecl *Function, AccessSpecifier Access, Expr **Args, unsigned NumArgs, @@ -961,7 +966,7 @@ public: bool SuppressUserConversions = false, bool ForceRValue = false, bool PartialOverloading = false); - void AddFunctionCandidates(const FunctionSet &Functions, + void AddFunctionCandidates(const UnresolvedSetImpl &Functions, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions = false); @@ -1029,6 +1034,7 @@ public: Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet); void AddArgumentDependentLookupCandidates(DeclarationName Name, + bool Operator, Expr **Args, unsigned NumArgs, const TemplateArgumentListInfo *ExplicitTemplateArgs, OverloadCandidateSet& CandidateSet, @@ -1080,12 +1086,12 @@ public: OwningExprResult CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned Opc, - FunctionSet &Functions, + const UnresolvedSetImpl &Fns, ExprArg input); OwningExprResult CreateOverloadedBinOp(SourceLocation OpLoc, unsigned Opc, - FunctionSet &Functions, + const UnresolvedSetImpl &Fns, Expr *LHS, Expr *RHS); OwningExprResult CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, @@ -1230,11 +1236,11 @@ public: void LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S, QualType T1, QualType T2, - FunctionSet &Functions); + UnresolvedSetImpl &Functions); void ArgumentDependentLookup(DeclarationName Name, bool Operator, Expr **Args, unsigned NumArgs, - FunctionSet &Functions); + ADLFunctionSet &Functions); void LookupVisibleDecls(Scope *S, LookupNameKind Kind, VisibleDeclConsumer &Consumer); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index e55fbe3d09..1d0374dcbb 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -6337,17 +6337,11 @@ Action::OwningExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc, // point. We perform both an operator-name lookup from the local // scope and an argument-dependent lookup based on the types of // the arguments. - FunctionSet Functions; + UnresolvedSet<16> Functions; OverloadedOperatorKind OverOp = BinaryOperator::getOverloadedOperator(Opc); - if (OverOp != OO_None) { - if (S) - LookupOverloadedOperatorName(OverOp, S, lhs->getType(), rhs->getType(), - Functions); - Expr *Args[2] = { lhs, rhs }; - DeclarationName OpName - = Context.DeclarationNames.getCXXOperatorName(OverOp); - ArgumentDependentLookup(OpName, /*Operator*/true, Args, 2, Functions); - } + if (S && OverOp != OO_None) + LookupOverloadedOperatorName(OverOp, S, lhs->getType(), rhs->getType(), + Functions); // Build the (potentially-overloaded, potentially-dependent) // binary operation. @@ -6456,16 +6450,11 @@ Action::OwningExprResult Sema::BuildUnaryOp(Scope *S, SourceLocation OpLoc, // point. We perform both an operator-name lookup from the local // scope and an argument-dependent lookup based on the types of // the arguments. - FunctionSet Functions; + UnresolvedSet<16> Functions; OverloadedOperatorKind OverOp = UnaryOperator::getOverloadedOperator(Opc); - if (OverOp != OO_None) { - if (S) - LookupOverloadedOperatorName(OverOp, S, Input->getType(), QualType(), - Functions); - DeclarationName OpName - = Context.DeclarationNames.getCXXOperatorName(OverOp); - ArgumentDependentLookup(OpName, /*Operator*/true, &Input, 1, Functions); - } + if (S && OverOp != OO_None) + LookupOverloadedOperatorName(OverOp, S, Input->getType(), QualType(), + Functions); return CreateOverloadedUnaryOp(OpLoc, Opc, Functions, move(input)); } diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index f5d2a7d899..5b03fa48c3 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -1693,7 +1693,7 @@ ObjCProtocolDecl *Sema::LookupProtocol(IdentifierInfo *II) { void Sema::LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S, QualType T1, QualType T2, - FunctionSet &Functions) { + UnresolvedSetImpl &Functions) { // C++ [over.match.oper]p3: // -- The set of non-member candidates is the result of the // unqualified lookup of operator@ in the context of the @@ -1719,29 +1719,21 @@ void Sema::LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S, Op != OpEnd; ++Op) { if (FunctionDecl *FD = dyn_cast(*Op)) { if (IsAcceptableNonMemberOperatorCandidate(FD, T1, T2, Context)) - Functions.insert(FD); // FIXME: canonical FD + Functions.addDecl(FD, Op.getAccess()); // FIXME: canonical FD } else if (FunctionTemplateDecl *FunTmpl = dyn_cast(*Op)) { // FIXME: friend operators? // FIXME: do we need to check IsAcceptableNonMemberOperatorCandidate, // later? if (!FunTmpl->getDeclContext()->isRecord()) - Functions.insert(FunTmpl); + Functions.addDecl(FunTmpl, Op.getAccess()); } } } -static void CollectFunctionDecl(Sema::FunctionSet &Functions, - Decl *D) { - if (FunctionDecl *Func = dyn_cast(D)) - Functions.insert(Func); - else if (FunctionTemplateDecl *FunTmpl = dyn_cast(D)) - Functions.insert(FunTmpl); -} - void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator, Expr **Args, unsigned NumArgs, - FunctionSet &Functions) { + ADLFunctionSet &Functions) { // Find all of the associated namespaces and classes based on the // arguments we have. AssociatedNamespaceSet AssociatedNamespaces; @@ -1784,7 +1776,7 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator, // lookup (11.4). DeclContext::lookup_iterator I, E; for (llvm::tie(I, E) = (*NS)->lookup(Name); I != E; ++I) { - Decl *D = *I; + NamedDecl *D = *I; // If the only declaration here is an ordinary friend, consider // it only if it was declared in an associated classes. if (D->getIdentifierNamespace() == Decl::IDNS_OrdinaryFriend) { @@ -1793,10 +1785,16 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator, continue; } + // FIXME: using decls? canonical decls? + FunctionDecl *Fn; if (!Operator || !(Fn = dyn_cast(D)) || - IsAcceptableNonMemberOperatorCandidate(Fn, T1, T2, Context)) - CollectFunctionDecl(Functions, D); + IsAcceptableNonMemberOperatorCandidate(Fn, T1, T2, Context)) { + if (isa(D)) + Functions.insert(D); + else if (isa(D)) + Functions.insert(D); + } } } } diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index a71ec5177d..54db885e23 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -2475,17 +2475,15 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, /// \brief Add all of the function declarations in the given function set to /// the overload canddiate set. -void Sema::AddFunctionCandidates(const FunctionSet &Functions, +void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions) { - for (FunctionSet::const_iterator F = Functions.begin(), - FEnd = Functions.end(); - F != FEnd; ++F) { + for (UnresolvedSetIterator F = Fns.begin(), E = Fns.end(); F != E; ++F) { // FIXME: using declarations if (FunctionDecl *FD = dyn_cast(*F)) { if (isa(FD) && !cast(FD)->isStatic()) - AddMethodCandidate(cast(FD), /*FIXME*/ FD->getAccess(), + AddMethodCandidate(cast(FD), F.getAccess(), cast(FD)->getParent(), Args[0]->getType(), Args + 1, NumArgs - 1, CandidateSet, SuppressUserConversions); @@ -2496,7 +2494,7 @@ void Sema::AddFunctionCandidates(const FunctionSet &Functions, FunctionTemplateDecl *FunTmpl = cast(*F); if (isa(FunTmpl->getTemplatedDecl()) && !cast(FunTmpl->getTemplatedDecl())->isStatic()) - AddMethodTemplateCandidate(FunTmpl, /*FIXME*/ FunTmpl->getAccess(), + AddMethodTemplateCandidate(FunTmpl, F.getAccess(), cast(FunTmpl->getDeclContext()), /*FIXME: explicit args */ 0, Args[0]->getType(), Args + 1, NumArgs - 1, @@ -2986,7 +2984,7 @@ void Sema::AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, SourceRange OpRange) { - FunctionSet Functions; + UnresolvedSet<16> Fns; QualType T1 = Args[0]->getType(); QualType T2; @@ -2995,9 +2993,10 @@ void Sema::AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S, DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op); if (S) - LookupOverloadedOperatorName(Op, S, T1, T2, Functions); - ArgumentDependentLookup(OpName, /*Operator*/true, Args, NumArgs, Functions); - AddFunctionCandidates(Functions, Args, NumArgs, CandidateSet); + LookupOverloadedOperatorName(Op, S, T1, T2, Fns); + AddFunctionCandidates(Fns, Args, NumArgs, CandidateSet, false); + AddArgumentDependentLookupCandidates(OpName, false, Args, NumArgs, 0, + CandidateSet); AddMemberOperatorCandidates(Op, OpLoc, Args, NumArgs, CandidateSet, OpRange); AddBuiltinOperatorCandidates(Op, OpLoc, Args, NumArgs, CandidateSet); } @@ -4127,31 +4126,19 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, /// candidate set (C++ [basic.lookup.argdep]). void Sema::AddArgumentDependentLookupCandidates(DeclarationName Name, + bool Operator, Expr **Args, unsigned NumArgs, const TemplateArgumentListInfo *ExplicitTemplateArgs, OverloadCandidateSet& CandidateSet, bool PartialOverloading) { - FunctionSet Functions; + ADLFunctionSet Functions; // FIXME: Should we be trafficking in canonical function decls throughout? - // Record all of the function candidates that we've already - // added to the overload set, so that we don't add those same - // candidates a second time. - for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(), - CandEnd = CandidateSet.end(); - Cand != CandEnd; ++Cand) - if (Cand->Function) { - Functions.insert(Cand->Function); - if (FunctionTemplateDecl *FunTmpl = Cand->Function->getPrimaryTemplate()) - Functions.insert(FunTmpl); - } - // FIXME: Pass in the explicit template arguments? - ArgumentDependentLookup(Name, /*Operator*/false, Args, NumArgs, Functions); + ArgumentDependentLookup(Name, Operator, Args, NumArgs, Functions); // Erase all of the candidates we already knew about. - // FIXME: This is suboptimal. Is there a better way? for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(), CandEnd = CandidateSet.end(); Cand != CandEnd; ++Cand) @@ -4163,17 +4150,16 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name, // For each of the ADL candidates we found, add it to the overload // set. - for (FunctionSet::iterator Func = Functions.begin(), - FuncEnd = Functions.end(); - Func != FuncEnd; ++Func) { - if (FunctionDecl *FD = dyn_cast(*Func)) { + for (ADLFunctionSet::iterator I = Functions.begin(), + E = Functions.end(); I != E; ++I) { + if (FunctionDecl *FD = dyn_cast(*I)) { if (ExplicitTemplateArgs) continue; AddOverloadCandidate(FD, AS_none, Args, NumArgs, CandidateSet, false, false, PartialOverloading); } else - AddTemplateOverloadCandidate(cast(*Func), + AddTemplateOverloadCandidate(cast(*I), AS_none, ExplicitTemplateArgs, Args, NumArgs, CandidateSet); } @@ -5242,7 +5228,8 @@ void Sema::AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE, PartialOverloading); if (ULE->requiresADL()) - AddArgumentDependentLookupCandidates(ULE->getName(), Args, NumArgs, + AddArgumentDependentLookupCandidates(ULE->getName(), /*Operator*/ false, + Args, NumArgs, ExplicitTemplateArgs, CandidateSet, PartialOverloading); @@ -5392,7 +5379,7 @@ Sema::BuildOverloadedCallExpr(Expr *Fn, UnresolvedLookupExpr *ULE, return ExprError(); } -static bool IsOverloaded(const Sema::FunctionSet &Functions) { +static bool IsOverloaded(const UnresolvedSetImpl &Functions) { return Functions.size() > 1 || (Functions.size() == 1 && isa(*Functions.begin())); } @@ -5413,10 +5400,10 @@ static bool IsOverloaded(const Sema::FunctionSet &Functions) { /// by CreateOverloadedUnaryOp(). /// /// \param input The input argument. -Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, - unsigned OpcIn, - FunctionSet &Functions, - ExprArg input) { +Sema::OwningExprResult +Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, + const UnresolvedSetImpl &Fns, + ExprArg input) { UnaryOperator::Opcode Opc = static_cast(OpcIn); Expr *Input = (Expr *)input.get(); @@ -5441,11 +5428,8 @@ Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnresolvedLookupExpr *Fn = UnresolvedLookupExpr::Create(Context, /*Dependent*/ true, 0, SourceRange(), OpName, OpLoc, - /*ADL*/ true, IsOverloaded(Functions)); - for (FunctionSet::iterator Func = Functions.begin(), - FuncEnd = Functions.end(); - Func != FuncEnd; ++Func) - Fn->addDecl(*Func); + /*ADL*/ true, IsOverloaded(Fns)); + Fn->addDecls(Fns.begin(), Fns.end()); input.release(); return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn, @@ -5458,11 +5442,17 @@ Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, OverloadCandidateSet CandidateSet; // Add the candidates from the given function set. - AddFunctionCandidates(Functions, &Args[0], NumArgs, CandidateSet, false); + AddFunctionCandidates(Fns, &Args[0], NumArgs, CandidateSet, false); // Add operator candidates that are member functions. AddMemberOperatorCandidates(Op, OpLoc, &Args[0], NumArgs, CandidateSet); + // Add candidates from ADL. + AddArgumentDependentLookupCandidates(OpName, /*Operator*/ true, + Args, 1, + /*ExplicitTemplateArgs*/ 0, + CandidateSet); + // Add builtin operator candidates. AddBuiltinOperatorCandidates(Op, OpLoc, &Args[0], NumArgs, CandidateSet); @@ -5575,7 +5565,7 @@ Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, Sema::OwningExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc, unsigned OpcIn, - FunctionSet &Functions, + const UnresolvedSetImpl &Fns, Expr *LHS, Expr *RHS) { Expr *Args[2] = { LHS, RHS }; LHS=RHS=0; //Please use only Args instead of LHS/RHS couple @@ -5587,7 +5577,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, // If either side is type-dependent, create an appropriate dependent // expression. if (Args[0]->isTypeDependent() || Args[1]->isTypeDependent()) { - if (Functions.empty()) { + if (Fns.empty()) { // If there are no functions to store, just build a dependent // BinaryOperator or CompoundAssignment. if (Opc <= BinaryOperator::Assign || Opc > BinaryOperator::OrAssign) @@ -5600,17 +5590,14 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, Context.DependentTy, OpLoc)); } - + + // FIXME: save results of ADL from here? UnresolvedLookupExpr *Fn = UnresolvedLookupExpr::Create(Context, /*Dependent*/ true, 0, SourceRange(), OpName, OpLoc, - /* ADL */ true, IsOverloaded(Functions)); - - for (FunctionSet::iterator Func = Functions.begin(), - FuncEnd = Functions.end(); - Func != FuncEnd; ++Func) - Fn->addDecl(*Func); + /*ADL*/ true, IsOverloaded(Fns)); + Fn->addDecls(Fns.begin(), Fns.end()); return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn, Args, 2, Context.DependentTy, @@ -5635,11 +5622,17 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, OverloadCandidateSet CandidateSet; // Add the candidates from the given function set. - AddFunctionCandidates(Functions, Args, 2, CandidateSet, false); + AddFunctionCandidates(Fns, Args, 2, CandidateSet, false); // Add operator candidates that are member functions. AddMemberOperatorCandidates(Op, OpLoc, Args, 2, CandidateSet); + // Add candidates from ADL. + AddArgumentDependentLookupCandidates(OpName, /*Operator*/ true, + Args, 2, + /*ExplicitTemplateArgs*/ 0, + CandidateSet); + // Add builtin operator candidates. AddBuiltinOperatorCandidates(Op, OpLoc, Args, 2, CandidateSet); diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 0158a08eb7..bd1b6e683d 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -5644,28 +5644,21 @@ TreeTransform::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op, // Compute the transformed set of functions (and function templates) to be // used during overload resolution. - Sema::FunctionSet Functions; + UnresolvedSet<16> Functions; if (UnresolvedLookupExpr *ULE = dyn_cast(CalleeExpr)) { assert(ULE->requiresADL()); // FIXME: Do we have to check // IsAcceptableNonMemberOperatorCandidate for each of these? - for (UnresolvedLookupExpr::decls_iterator I = ULE->decls_begin(), - E = ULE->decls_end(); I != E; ++I) - Functions.insert(AnyFunctionDecl::getFromNamedDecl(*I)); + Functions.append(ULE->decls_begin(), ULE->decls_end()); } else { - Functions.insert(AnyFunctionDecl::getFromNamedDecl( - cast(CalleeExpr)->getDecl())); + Functions.addDecl(cast(CalleeExpr)->getDecl()); } // Add any functions found via argument-dependent lookup. Expr *Args[2] = { FirstExpr, SecondExpr }; unsigned NumArgs = 1 + (SecondExpr != 0); - DeclarationName OpName - = SemaRef.Context.DeclarationNames.getCXXOperatorName(Op); - SemaRef.ArgumentDependentLookup(OpName, /*Operator*/true, Args, NumArgs, - Functions); // Create the overloaded operator invocation for unary operators. if (NumArgs == 1 || isPostIncDec) { -- 2.50.1