diff --git a/clang/include/clang/AST/ASTImporter.h b/clang/include/clang/AST/ASTImporter.h --- a/clang/include/clang/AST/ASTImporter.h +++ b/clang/include/clang/AST/ASTImporter.h @@ -480,6 +480,13 @@ /// error. llvm::Expected Import(const APValue &FromValue); + /// Import the given C++ TemplateArgumentList from the "from" + /// context into the "to" context. + /// + /// \returns The equivalent initializer in the "to" context, or the import + /// error. + llvm::Expected Import(const TemplateArgumentList *); + /// Import the definition of the given declaration, including all of /// the declarations it contains. [[nodiscard]] llvm::Error ImportDefinition(Decl *From); diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -3175,6 +3175,8 @@ /// In X.F, this is the decl referenced by F. ValueDecl *MemberDecl; + const TemplateArgumentList *Deduced; + /// MemberDNLoc - Provides source/type location info for the /// declaration name embedded in MemberDecl. DeclarationNameLoc MemberDNLoc; @@ -3200,21 +3202,20 @@ MemberExpr(Expr *Base, bool IsArrow, SourceLocation OperatorLoc, ValueDecl *MemberDecl, const DeclarationNameInfo &NameInfo, - QualType T, ExprValueKind VK, ExprObjectKind OK, - NonOdrUseReason NOUR); + const TemplateArgumentList *Deduced, QualType T, ExprValueKind VK, + ExprObjectKind OK, NonOdrUseReason NOUR); MemberExpr(EmptyShell Empty) : Expr(MemberExprClass, Empty), Base(), MemberDecl() {} public: - static MemberExpr *Create(const ASTContext &C, Expr *Base, bool IsArrow, - SourceLocation OperatorLoc, - NestedNameSpecifierLoc QualifierLoc, - SourceLocation TemplateKWLoc, ValueDecl *MemberDecl, - DeclAccessPair FoundDecl, - DeclarationNameInfo MemberNameInfo, - const TemplateArgumentListInfo *TemplateArgs, - QualType T, ExprValueKind VK, ExprObjectKind OK, - NonOdrUseReason NOUR); + static MemberExpr * + Create(const ASTContext &C, Expr *Base, bool IsArrow, + SourceLocation OperatorLoc, NestedNameSpecifierLoc QualifierLoc, + SourceLocation TemplateKWLoc, ValueDecl *MemberDecl, + DeclAccessPair FoundDecl, DeclarationNameInfo MemberNameInfo, + const TemplateArgumentListInfo *TemplateArgs, + const TemplateArgumentList *Deduced, QualType T, ExprValueKind VK, + ExprObjectKind OK, NonOdrUseReason NOUR); /// Create an implicit MemberExpr, with no location, qualifier, template /// arguments, and so on. Suitable only for non-static member access. @@ -3225,7 +3226,8 @@ return Create(C, Base, IsArrow, SourceLocation(), NestedNameSpecifierLoc(), SourceLocation(), MemberDecl, DeclAccessPair::make(MemberDecl, MemberDecl->getAccess()), - DeclarationNameInfo(), nullptr, T, VK, OK, NOUR_None); + DeclarationNameInfo(), nullptr, nullptr, T, VK, OK, + NOUR_None); } static MemberExpr *CreateEmpty(const ASTContext &Context, bool HasQualifier, @@ -3251,6 +3253,8 @@ return getTrailingObjects()->FoundDecl; } + const TemplateArgumentList *getDeduced() const { return Deduced; } + /// Determines whether this member expression actually had /// a C++ nested-name-specifier prior to the name of the member, e.g., /// x->Base::foo. diff --git a/clang/include/clang/Sema/Overload.h b/clang/include/clang/Sema/Overload.h --- a/clang/include/clang/Sema/Overload.h +++ b/clang/include/clang/Sema/Overload.h @@ -885,6 +885,9 @@ StandardConversionSequence FinalConversion; }; + /// Deduced Arguments for Function Templates. + const TemplateArgumentList *Deduced; + /// Get RewriteKind value in OverloadCandidateRewriteKind type (This /// function is to workaround the spurious GCC bitfield enum warning) OverloadCandidateRewriteKind getRewriteKind() const { diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -3882,7 +3882,8 @@ bool AllowExplicitConversion = false, ADLCallKind IsADLCandidate = ADLCallKind::NotADL, ConversionSequenceList EarlyConversions = None, - OverloadCandidateParamOrder PO = {}); + OverloadCandidateParamOrder PO = {}, + const TemplateArgumentList *Deduced = nullptr); void AddFunctionCandidates(const UnresolvedSetImpl &Functions, ArrayRef Args, OverloadCandidateSet &CandidateSet, @@ -3897,16 +3898,16 @@ OverloadCandidateSet& CandidateSet, bool SuppressUserConversion = false, OverloadCandidateParamOrder PO = {}); - void AddMethodCandidate(CXXMethodDecl *Method, - DeclAccessPair FoundDecl, + void AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, QualType ObjectType, Expr::Classification ObjectClassification, ArrayRef Args, - OverloadCandidateSet& CandidateSet, + OverloadCandidateSet &CandidateSet, bool SuppressUserConversions = false, bool PartialOverloading = false, ConversionSequenceList EarlyConversions = None, - OverloadCandidateParamOrder PO = {}); + OverloadCandidateParamOrder PO = {}, + const TemplateArgumentList *Deduced = nullptr); void AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, @@ -4042,10 +4043,9 @@ bool resolveAndFixAddressOfSingleOverloadCandidate( ExprResult &SrcExpr, bool DoFunctionPointerConversion = false); - FunctionDecl * - ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl, - bool Complain = false, - DeclAccessPair *Found = nullptr); + FunctionDecl *ResolveSingleFunctionTemplateSpecialization( + OverloadExpr *ovl, TemplateArgumentListInfo &ExplicitTemplateArgs, + bool Complain = false, DeclAccessPair *Found = nullptr); bool ResolveAndFixSingleFunctionTemplateSpecialization( ExprResult &SrcExpr, bool DoFunctionPointerConversion = false, @@ -4053,12 +4053,13 @@ QualType DestTypeForComplaining = QualType(), unsigned DiagIDForComplaining = 0); - Expr *FixOverloadedFunctionReference(Expr *E, - DeclAccessPair FoundDecl, - FunctionDecl *Fn); - ExprResult FixOverloadedFunctionReference(ExprResult, - DeclAccessPair FoundDecl, - FunctionDecl *Fn); + Expr *FixOverloadedFunctionReference(Expr *E, DeclAccessPair FoundDecl, + FunctionDecl *Fn, + const TemplateArgumentList *Deduced); + ExprResult + FixOverloadedFunctionReference(ExprResult, DeclAccessPair FoundDecl, + FunctionDecl *Fn, + const TemplateArgumentList *Deduced); void AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE, ArrayRef Args, @@ -5703,22 +5704,20 @@ UnqualifiedId &Member, Decl *ObjCImpDecl); - MemberExpr * - BuildMemberExpr(Expr *Base, bool IsArrow, SourceLocation OpLoc, - const CXXScopeSpec *SS, SourceLocation TemplateKWLoc, - ValueDecl *Member, DeclAccessPair FoundDecl, - bool HadMultipleCandidates, - const DeclarationNameInfo &MemberNameInfo, QualType Ty, - ExprValueKind VK, ExprObjectKind OK, - const TemplateArgumentListInfo *TemplateArgs = nullptr); - MemberExpr * - BuildMemberExpr(Expr *Base, bool IsArrow, SourceLocation OpLoc, - NestedNameSpecifierLoc NNS, SourceLocation TemplateKWLoc, - ValueDecl *Member, DeclAccessPair FoundDecl, - bool HadMultipleCandidates, - const DeclarationNameInfo &MemberNameInfo, QualType Ty, - ExprValueKind VK, ExprObjectKind OK, - const TemplateArgumentListInfo *TemplateArgs = nullptr); + MemberExpr *BuildMemberExpr( + Expr *Base, bool IsArrow, SourceLocation OpLoc, const CXXScopeSpec *SS, + SourceLocation TemplateKWLoc, ValueDecl *Member, DeclAccessPair FoundDecl, + bool HadMultipleCandidates, const DeclarationNameInfo &MemberNameInfo, + QualType Ty, ExprValueKind VK, ExprObjectKind OK, + const TemplateArgumentListInfo *TemplateArgs = nullptr, + const TemplateArgumentList *Deduced = nullptr); + MemberExpr *BuildMemberExpr( + Expr *Base, bool IsArrow, SourceLocation OpLoc, + NestedNameSpecifierLoc NNS, SourceLocation TemplateKWLoc, + ValueDecl *Member, DeclAccessPair FoundDecl, bool HadMultipleCandidates, + const DeclarationNameInfo &MemberNameInfo, QualType Ty, ExprValueKind VK, + ExprObjectKind OK, const TemplateArgumentListInfo *TemplateArgs = nullptr, + const TemplateArgumentList *Deduced = nullptr); void ActOnDefaultCtorInitializers(Decl *CDtorDecl); bool ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -7951,6 +7951,7 @@ auto ToQualifierLoc = importChecked(Err, E->getQualifierLoc()); auto ToTemplateKeywordLoc = importChecked(Err, E->getTemplateKeywordLoc()); auto ToMemberDecl = importChecked(Err, E->getMemberDecl()); + auto ToDeduced = importChecked(Err, E->getDeduced()); auto ToType = importChecked(Err, E->getType()); auto ToDecl = importChecked(Err, E->getFoundDecl().getDecl()); auto ToName = importChecked(Err, E->getMemberNameInfo().getName()); @@ -7975,7 +7976,7 @@ return MemberExpr::Create(Importer.getToContext(), ToBase, E->isArrow(), ToOperatorLoc, ToQualifierLoc, ToTemplateKeywordLoc, ToMemberDecl, ToFoundDecl, ToMemberNameInfo, - ResInfo, ToType, E->getValueKind(), + ResInfo, ToDeduced, ToType, E->getValueKind(), E->getObjectKind(), E->isNonOdrUse()); } @@ -9655,6 +9656,17 @@ return Importer.ImportAPValue(FromValue); } +llvm::Expected +ASTImporter::Import(const TemplateArgumentList *ArgList) { + ASTNodeImporter Importer(*this); + if (!ArgList) + return nullptr; + SmallVector ToArgs(ArgList->size()); + if (auto Res = Importer.ImportTemplateArguments(ArgList->asArray(), ToArgs)) + return std::move(Res); + return TemplateArgumentList::CreateCopy(ToContext, ToArgs); +} + Error ASTImporter::ImportDefinition(Decl *From) { ExpectedDecl ToOrErr = Import(From); if (!ToOrErr) diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -1612,11 +1612,13 @@ MemberExpr::MemberExpr(Expr *Base, bool IsArrow, SourceLocation OperatorLoc, ValueDecl *MemberDecl, - const DeclarationNameInfo &NameInfo, QualType T, + const DeclarationNameInfo &NameInfo, + const TemplateArgumentList *Deduced, QualType T, ExprValueKind VK, ExprObjectKind OK, NonOdrUseReason NOUR) : Expr(MemberExprClass, T, VK, OK), Base(Base), MemberDecl(MemberDecl), - MemberDNLoc(NameInfo.getInfo()), MemberLoc(NameInfo.getLoc()) { + Deduced(Deduced), MemberDNLoc(NameInfo.getInfo()), + MemberLoc(NameInfo.getLoc()) { assert(!NameInfo.getName() || MemberDecl->getDeclName() == NameInfo.getName()); MemberExprBits.IsArrow = IsArrow; @@ -1633,7 +1635,8 @@ NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, ValueDecl *MemberDecl, DeclAccessPair FoundDecl, DeclarationNameInfo NameInfo, const TemplateArgumentListInfo *TemplateArgs, - QualType T, ExprValueKind VK, ExprObjectKind OK, NonOdrUseReason NOUR) { + const TemplateArgumentList *Deduced, QualType T, ExprValueKind VK, + ExprObjectKind OK, NonOdrUseReason NOUR) { bool HasQualOrFound = QualifierLoc || FoundDecl.getDecl() != MemberDecl || FoundDecl.getAccess() != MemberDecl->getAccess(); bool HasTemplateKWAndArgsInfo = TemplateArgs || TemplateKWLoc.isValid(); @@ -1645,7 +1648,7 @@ void *Mem = C.Allocate(Size, alignof(MemberExpr)); MemberExpr *E = new (Mem) MemberExpr(Base, IsArrow, OperatorLoc, MemberDecl, - NameInfo, T, VK, OK, NOUR); + NameInfo, Deduced, T, VK, OK, NOUR); // FIXME: remove remaining dependence computation to computeDependence(). auto Deps = E->getDependence(); diff --git a/clang/lib/Analysis/BodyFarm.cpp b/clang/lib/Analysis/BodyFarm.cpp --- a/clang/lib/Analysis/BodyFarm.cpp +++ b/clang/lib/Analysis/BodyFarm.cpp @@ -230,8 +230,8 @@ C, base, IsArrow, SourceLocation(), NestedNameSpecifierLoc(), SourceLocation(), MemberDecl, FoundDecl, DeclarationNameInfo(MemberDecl->getDeclName(), SourceLocation()), - /* TemplateArgumentListInfo=*/ nullptr, MemberDecl->getType(), ValueKind, - OK_Ordinary, NOUR_None); + /* TemplateArgumentListInfo=*/nullptr, /*Deduced=*/nullptr, + MemberDecl->getType(), ValueKind, OK_Ordinary, NOUR_None); } ValueDecl *ASTMaker::findMemberField(const RecordDecl *RD, StringRef Name) { diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp --- a/clang/lib/Sema/SemaCast.cpp +++ b/clang/lib/Sema/SemaCast.cpp @@ -1808,7 +1808,8 @@ return TC_Failed; } - SrcExpr = Self.FixOverloadedFunctionReference(SrcExpr, FoundOverload, Fn); + SrcExpr = Self.FixOverloadedFunctionReference(SrcExpr, FoundOverload, Fn, + nullptr); if (!SrcExpr.isUsable()) { msg = 0; return TC_Failed; @@ -2885,7 +2886,8 @@ DeclAccessPair DAP; if (FunctionDecl *FD = Self.ResolveAddressOfOverloadedFunction( SrcExpr.get(), DestType, /*Complain=*/true, DAP)) - SrcExpr = Self.FixOverloadedFunctionReference(SrcExpr.get(), DAP, FD); + SrcExpr = + Self.FixOverloadedFunctionReference(SrcExpr.get(), DAP, FD, nullptr); else return; assert(SrcExpr.isUsable()); diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -3599,9 +3599,13 @@ return; } } else if (auto *ULE = dyn_cast(E)) { - if (ULE->hasExplicitTemplateArgs()) + if (ULE->hasExplicitTemplateArgs()) { S.Diag(Loc, diag::warn_cleanup_ext); - FD = S.ResolveSingleFunctionTemplateSpecialization(ULE, true); + TemplateArgumentListInfo ExplicitTemplateArgs; + ULE->copyTemplateArgumentsInto(ExplicitTemplateArgs); + FD = S.ResolveSingleFunctionTemplateSpecialization( + ULE, ExplicitTemplateArgs, /*Complain=*/true); + } NI = ULE->getNameInfo(); if (!FD) { S.Diag(Loc, diag::err_attribute_cleanup_arg_not_function) << 2 diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -9967,7 +9967,7 @@ DeclAccessPair DAP; if (FunctionDecl *FD = ResolveAddressOfOverloadedFunction( RHS.get(), LHSType, /*Complain=*/false, DAP)) - RHS = FixOverloadedFunctionReference(RHS.get(), DAP, FD); + RHS = FixOverloadedFunctionReference(RHS.get(), DAP, FD, nullptr); else return Incompatible; } @@ -14258,14 +14258,18 @@ } OverloadExpr *Ovl = cast(E); - if (isa(Ovl)) - if (!ResolveSingleFunctionTemplateSpecialization(Ovl)) { - Diag(OpLoc, diag::err_invalid_form_pointer_member_function) - << OrigOp.get()->getSourceRange(); - return QualType(); - } - - return Context.OverloadTy; + if (!isa(Ovl)) + return Context.OverloadTy; + if (Ovl->hasExplicitTemplateArgs()) { + TemplateArgumentListInfo ExplicitTemplateArgs; + Ovl->copyTemplateArgumentsInto(ExplicitTemplateArgs); + if (ResolveSingleFunctionTemplateSpecialization(Ovl, + ExplicitTemplateArgs)) + return Context.OverloadTy; + } + Diag(OpLoc, diag::err_invalid_form_pointer_member_function) + << OrigOp.get()->getSourceRange(); + return QualType(); } if (PTy->getKind() == BuiltinType::UnknownAny) @@ -19183,8 +19187,8 @@ S.Context, Base.get(), ME->isArrow(), ME->getOperatorLoc(), ME->getQualifierLoc(), ME->getTemplateKeywordLoc(), ME->getMemberDecl(), ME->getFoundDecl(), ME->getMemberNameInfo(), - CopiedTemplateArgs(ME), ME->getType(), ME->getValueKind(), - ME->getObjectKind(), ME->isNonOdrUse()); + CopiedTemplateArgs(ME), ME->getDeduced(), ME->getType(), + ME->getValueKind(), ME->getObjectKind(), ME->isNonOdrUse()); } if (ME->getMemberDecl()->isCXXInstanceMember()) @@ -19201,7 +19205,8 @@ S.Context, ME->getBase(), ME->isArrow(), ME->getOperatorLoc(), ME->getQualifierLoc(), ME->getTemplateKeywordLoc(), ME->getMemberDecl(), ME->getFoundDecl(), ME->getMemberNameInfo(), CopiedTemplateArgs(ME), - ME->getType(), ME->getValueKind(), ME->getObjectKind(), NOUR); + ME->getDeduced(), ME->getType(), ME->getValueKind(), + ME->getObjectKind(), NOUR); } case Expr::BinaryOperatorClass: { diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -4250,7 +4250,7 @@ if (DiagnoseUseOfDecl(Fn, From->getBeginLoc())) return ExprError(); - From = FixOverloadedFunctionReference(From, Found, Fn); + From = FixOverloadedFunctionReference(From, Found, Fn, nullptr); // We might get back another placeholder expression if we resolved to a // builtin. diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp --- a/clang/lib/Sema/SemaExprMember.cpp +++ b/clang/lib/Sema/SemaExprMember.cpp @@ -897,12 +897,13 @@ SourceLocation TemplateKWLoc, ValueDecl *Member, DeclAccessPair FoundDecl, bool HadMultipleCandidates, const DeclarationNameInfo &MemberNameInfo, QualType Ty, ExprValueKind VK, ExprObjectKind OK, - const TemplateArgumentListInfo *TemplateArgs) { + const TemplateArgumentListInfo *TemplateArgs, + const TemplateArgumentList *Deduced) { NestedNameSpecifierLoc NNS = SS ? SS->getWithLocInContext(Context) : NestedNameSpecifierLoc(); return BuildMemberExpr(Base, IsArrow, OpLoc, NNS, TemplateKWLoc, Member, FoundDecl, HadMultipleCandidates, MemberNameInfo, Ty, - VK, OK, TemplateArgs); + VK, OK, TemplateArgs, Deduced); } MemberExpr *Sema::BuildMemberExpr( @@ -910,13 +911,14 @@ SourceLocation TemplateKWLoc, ValueDecl *Member, DeclAccessPair FoundDecl, bool HadMultipleCandidates, const DeclarationNameInfo &MemberNameInfo, QualType Ty, ExprValueKind VK, ExprObjectKind OK, - const TemplateArgumentListInfo *TemplateArgs) { + const TemplateArgumentListInfo *TemplateArgs, + const TemplateArgumentList *Deduced) { assert((!IsArrow || Base->isPRValue()) && "-> base must be a pointer prvalue"); - MemberExpr *E = - MemberExpr::Create(Context, Base, IsArrow, OpLoc, NNS, TemplateKWLoc, - Member, FoundDecl, MemberNameInfo, TemplateArgs, Ty, - VK, OK, getNonOdrUseReasonInCurrentContext(Member)); + MemberExpr *E = MemberExpr::Create( + Context, Base, IsArrow, OpLoc, NNS, TemplateKWLoc, Member, FoundDecl, + MemberNameInfo, TemplateArgs, Deduced, Ty, VK, OK, + getNonOdrUseReasonInCurrentContext(Member)); E->setHadMultipleCandidates(HadMultipleCandidates); MarkMemberReferenced(E); diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -8261,9 +8261,8 @@ S.CheckAddressOfMemberAccess(CurInit.get(), Step->Function.FoundDecl); if (S.DiagnoseUseOfDecl(Step->Function.FoundDecl, Kind.getLocation())) return ExprError(); - CurInit = S.FixOverloadedFunctionReference(CurInit, - Step->Function.FoundDecl, - Step->Function.Function); + CurInit = S.FixOverloadedFunctionReference( + CurInit, Step->Function.FoundDecl, Step->Function.Function, nullptr); // We might get back another placeholder expression if we resolved to a // builtin. if (!CurInit.isInvalid()) diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -6332,7 +6332,7 @@ OverloadCandidateSet &CandidateSet, bool SuppressUserConversions, bool PartialOverloading, bool AllowExplicit, bool AllowExplicitConversions, ADLCallKind IsADLCandidate, ConversionSequenceList EarlyConversions, - OverloadCandidateParamOrder PO) { + OverloadCandidateParamOrder PO, const TemplateArgumentList *Deduced) { const FunctionProtoType *Proto = dyn_cast(Function->getType()->getAs()); assert(Proto && "Functions without a prototype cannot be overloaded"); @@ -6351,7 +6351,7 @@ AddMethodCandidate(Method, FoundDecl, Method->getParent(), QualType(), Expr::Classification::makeSimpleLValue(), Args, CandidateSet, SuppressUserConversions, - PartialOverloading, EarlyConversions, PO); + PartialOverloading, EarlyConversions, PO, Deduced); return; } // We treat a constructor like a non-member function, since its object @@ -6396,6 +6396,7 @@ Candidate.IsADLCandidate = IsADLCandidate; Candidate.IgnoreObjectArgument = false; Candidate.ExplicitCallArguments = Args.size(); + Candidate.Deduced = Deduced; // Explicit functions are not actually candidates at all if we're not // allowing them in this context, but keep them around so we can point @@ -6930,16 +6931,13 @@ /// both @c a1 and @c a2. If @p SuppressUserConversions, then don't /// allow user-defined conversions via constructors or conversion /// operators. -void -Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, - CXXRecordDecl *ActingContext, QualType ObjectType, - Expr::Classification ObjectClassification, - ArrayRef Args, - OverloadCandidateSet &CandidateSet, - bool SuppressUserConversions, - bool PartialOverloading, - ConversionSequenceList EarlyConversions, - OverloadCandidateParamOrder PO) { +void Sema::AddMethodCandidate( + CXXMethodDecl *Method, DeclAccessPair FoundDecl, + CXXRecordDecl *ActingContext, QualType ObjectType, + Expr::Classification ObjectClassification, ArrayRef Args, + OverloadCandidateSet &CandidateSet, bool SuppressUserConversions, + bool PartialOverloading, ConversionSequenceList EarlyConversions, + OverloadCandidateParamOrder PO, const TemplateArgumentList *Deduced) { const FunctionProtoType *Proto = dyn_cast(Method->getType()->getAs()); assert(Proto && "Methods without a prototype cannot be overloaded"); @@ -6970,6 +6968,7 @@ Candidate.IsSurrogate = false; Candidate.IgnoreObjectArgument = false; Candidate.ExplicitCallArguments = Args.size(); + Candidate.Deduced = Deduced; unsigned NumParams = Proto->getNumParams(); @@ -7146,7 +7145,7 @@ AddMethodCandidate(cast(Specialization), FoundDecl, ActingContext, ObjectType, ObjectClassification, Args, CandidateSet, SuppressUserConversions, PartialOverloading, - Conversions, PO); + Conversions, PO, Info.takeSugared()); } /// Determine whether a given function template has a simple explicit specifier @@ -7226,10 +7225,11 @@ // Add the function template specialization produced by template argument // deduction as a candidate. assert(Specialization && "Missing function template specialization?"); - AddOverloadCandidate( - Specialization, FoundDecl, Args, CandidateSet, SuppressUserConversions, - PartialOverloading, AllowExplicit, - /*AllowExplicitConversions*/ false, IsADLCandidate, Conversions, PO); + AddOverloadCandidate(Specialization, FoundDecl, Args, CandidateSet, + SuppressUserConversions, PartialOverloading, + AllowExplicit, + /*AllowExplicitConversions*/ false, IsADLCandidate, + Conversions, PO, Info.takeSugared()); } /// Check that implicit conversion sequences can be formed for each argument @@ -12075,15 +12075,20 @@ FailedCandidates(OvlExpr->getNameLoc(), /*ForTakingAddress=*/true) { ExtractUnqualifiedFunctionTypeFromTargetType(); + if (OvlExpr->hasExplicitTemplateArgs()) + OvlExpr->copyTemplateArgumentsInto(OvlExplicitTemplateArgs); + if (TargetFunctionType->isFunctionType()) { if (UnresolvedMemberExpr *UME = dyn_cast(OvlExpr)) if (!UME->isImplicitAccess() && - !S.ResolveSingleFunctionTemplateSpecialization(UME)) + (!OvlExpr->hasExplicitTemplateArgs() || + !S.ResolveSingleFunctionTemplateSpecialization( + UME, OvlExplicitTemplateArgs))) StaticMemberFunctionFromBoundPointer = true; } else if (OvlExpr->hasExplicitTemplateArgs()) { DeclAccessPair dap; if (FunctionDecl *Fn = S.ResolveSingleFunctionTemplateSpecialization( - OvlExpr, false, &dap)) { + OvlExpr, OvlExplicitTemplateArgs, /*Complain=*/false, &dap)) { if (CXXMethodDecl *Method = dyn_cast(Fn)) if (!Method->isStatic()) { // If the target type is a non-function type and the function found @@ -12102,9 +12107,6 @@ return; } - if (OvlExpr->hasExplicitTemplateArgs()) - OvlExpr->copyTemplateArgumentsInto(OvlExplicitTemplateArgs); - if (FindAllFunctionsThatMatchTargetTypeExactly()) { // C++ [over.over]p4: // If more than one function is selected, [...] @@ -12590,7 +12592,7 @@ // for both. DiagnoseUseOfDecl(Found, E->getExprLoc()); CheckAddressOfMemberAccess(E, DAP); - Expr *Fixed = FixOverloadedFunctionReference(E, DAP, Found); + Expr *Fixed = FixOverloadedFunctionReference(E, DAP, Found, nullptr); if (DoFunctionPointerConversion && Fixed->getType()->isFunctionType()) SrcExpr = DefaultFunctionArrayConversion(Fixed, /*Diagnose=*/false); else @@ -12608,10 +12610,9 @@ /// /// If no template-ids are found, no diagnostics are emitted and NULL is /// returned. -FunctionDecl * -Sema::ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl, - bool Complain, - DeclAccessPair *FoundResult) { +FunctionDecl *Sema::ResolveSingleFunctionTemplateSpecialization( + OverloadExpr *ovl, TemplateArgumentListInfo &ExplicitTemplateArgs, + bool Complain, DeclAccessPair *FoundResult) { // C++ [over.over]p1: // [...] [Note: any redundant set of parentheses surrounding the // overloaded function name is ignored (5.1). ] @@ -12619,12 +12620,9 @@ // [...] The overloaded function name can be preceded by the & // operator. - // If we didn't actually find any template-ids, we're done. - if (!ovl->hasExplicitTemplateArgs()) - return nullptr; + // Specializations must have template args. + assert(ovl->hasExplicitTemplateArgs()); - TemplateArgumentListInfo ExplicitTemplateArgs; - ovl->copyTemplateArgumentsInto(ExplicitTemplateArgs); TemplateSpecCandidateSet FailedCandidates(ovl->getNameLoc()); // Look through all of the overloaded functions, searching for one @@ -12699,50 +12697,53 @@ assert(SrcExpr.get()->getType() == Context.OverloadTy); OverloadExpr::FindResult ovl = OverloadExpr::find(SrcExpr.get()); - - DeclAccessPair found; ExprResult SingleFunctionExpression; - if (FunctionDecl *fn = ResolveSingleFunctionTemplateSpecialization( - ovl.Expression, /*complain*/ false, &found)) { - if (DiagnoseUseOfDecl(fn, SrcExpr.get()->getBeginLoc())) { - SrcExpr = ExprError(); - return true; - } + if (ovl.Expression->hasExplicitTemplateArgs()) { + TemplateArgumentListInfo ExplicitTemplateArgs; + ovl.Expression->copyTemplateArgumentsInto(ExplicitTemplateArgs); + + DeclAccessPair found; + if (FunctionDecl *fn = ResolveSingleFunctionTemplateSpecialization( + ovl.Expression, ExplicitTemplateArgs, /*Complain=*/false, &found)) { + if (DiagnoseUseOfDecl(fn, SrcExpr.get()->getBeginLoc())) { + SrcExpr = ExprError(); + return true; + } - // It is only correct to resolve to an instance method if we're - // resolving a form that's permitted to be a pointer to member. - // Otherwise we'll end up making a bound member expression, which - // is illegal in all the contexts we resolve like this. - if (!ovl.HasFormOfMemberPointer && - isa(fn) && - cast(fn)->isInstance()) { - if (!complain) return false; - - Diag(ovl.Expression->getExprLoc(), - diag::err_bound_member_function) - << 0 << ovl.Expression->getSourceRange(); - - // TODO: I believe we only end up here if there's a mix of - // static and non-static candidates (otherwise the expression - // would have 'bound member' type, not 'overload' type). - // Ideally we would note which candidate was chosen and why - // the static candidates were rejected. - SrcExpr = ExprError(); - return true; - } + // It is only correct to resolve to an instance method if we're + // resolving a form that's permitted to be a pointer to member. + // Otherwise we'll end up making a bound member expression, which + // is illegal in all the contexts we resolve like this. + if (!ovl.HasFormOfMemberPointer && isa(fn) && + cast(fn)->isInstance()) { + if (!complain) + return false; - // Fix the expression to refer to 'fn'. - SingleFunctionExpression = - FixOverloadedFunctionReference(SrcExpr.get(), found, fn); + Diag(ovl.Expression->getExprLoc(), diag::err_bound_member_function) + << 0 << ovl.Expression->getSourceRange(); - // If desired, do function-to-pointer decay. - if (doFunctionPointerConversion) { - SingleFunctionExpression = - DefaultFunctionArrayLvalueConversion(SingleFunctionExpression.get()); - if (SingleFunctionExpression.isInvalid()) { + // TODO: I believe we only end up here if there's a mix of + // static and non-static candidates (otherwise the expression + // would have 'bound member' type, not 'overload' type). + // Ideally we would note which candidate was chosen and why + // the static candidates were rejected. SrcExpr = ExprError(); return true; } + + // Fix the expression to refer to 'fn'. + SingleFunctionExpression = + FixOverloadedFunctionReference(SrcExpr.get(), found, fn, nullptr); + + // If desired, do function-to-pointer decay. + if (doFunctionPointerConversion) { + SingleFunctionExpression = DefaultFunctionArrayLvalueConversion( + SingleFunctionExpression.get()); + if (SingleFunctionExpression.isInvalid()) { + SrcExpr = ExprError(); + return true; + } + } } } @@ -13255,7 +13256,8 @@ SemaRef.CheckUnresolvedLookupAccess(ULE, (*Best)->FoundDecl); if (SemaRef.DiagnoseUseOfDecl(FDecl, ULE->getNameLoc())) return ExprError(); - Fn = SemaRef.FixOverloadedFunctionReference(Fn, (*Best)->FoundDecl, FDecl); + Fn = SemaRef.FixOverloadedFunctionReference(Fn, (*Best)->FoundDecl, FDecl, + (*Best)->Deduced); return SemaRef.BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, RParenLoc, ExecConfig, /*IsExecConfig=*/false, (*Best)->IsADLCandidate); @@ -13313,7 +13315,8 @@ // We emitted an error for the unavailable/deleted function call but keep // the call in the AST. FunctionDecl *FDecl = (*Best)->Function; - Fn = SemaRef.FixOverloadedFunctionReference(Fn, (*Best)->FoundDecl, FDecl); + Fn = SemaRef.FixOverloadedFunctionReference(Fn, (*Best)->FoundDecl, FDecl, + (*Best)->Deduced); return SemaRef.BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, RParenLoc, ExecConfig, /*IsExecConfig=*/false, (*Best)->IsADLCandidate); @@ -14581,7 +14584,8 @@ if (!Succeeded) return BuildRecoveryExpr(chooseRecoveryType(CandidateSet, &Best)); - MemExprE = FixOverloadedFunctionReference(MemExprE, FoundDecl, Method); + MemExprE = FixOverloadedFunctionReference(MemExprE, FoundDecl, Method, + Best->Deduced); // If overload resolution picked a static member, build a // non-member call based on that function. @@ -15196,11 +15200,13 @@ /// perhaps a '&' around it). We have resolved the overloaded function /// to the function declaration Fn, so patch up the expression E to /// refer (possibly indirectly) to Fn. Returns the new expr. -Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found, - FunctionDecl *Fn) { +Expr * +Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found, + FunctionDecl *Fn, + const TemplateArgumentList *Deduced) { if (ParenExpr *PE = dyn_cast(E)) { - Expr *SubExpr = FixOverloadedFunctionReference(PE->getSubExpr(), - Found, Fn); + Expr *SubExpr = + FixOverloadedFunctionReference(PE->getSubExpr(), Found, Fn, Deduced); if (SubExpr == PE->getSubExpr()) return PE; @@ -15208,8 +15214,8 @@ } if (ImplicitCastExpr *ICE = dyn_cast(E)) { - Expr *SubExpr = FixOverloadedFunctionReference(ICE->getSubExpr(), - Found, Fn); + Expr *SubExpr = + FixOverloadedFunctionReference(ICE->getSubExpr(), Found, Fn, Deduced); assert(Context.hasSameType(ICE->getSubExpr()->getType(), SubExpr->getType()) && "Implicit cast type cannot be determined from overload"); @@ -15224,8 +15230,8 @@ if (auto *GSE = dyn_cast(E)) { if (!GSE->isResultDependent()) { - Expr *SubExpr = - FixOverloadedFunctionReference(GSE->getResultExpr(), Found, Fn); + Expr *SubExpr = FixOverloadedFunctionReference(GSE->getResultExpr(), + Found, Fn, Deduced); if (SubExpr == GSE->getResultExpr()) return GSE; @@ -15259,7 +15265,7 @@ // UnresolvedLookupExpr holding an overloaded member function // or template. Expr *SubExpr = FixOverloadedFunctionReference(UnOp->getSubExpr(), - Found, Fn); + Found, Fn, Deduced); if (SubExpr == UnOp->getSubExpr()) return UnOp; @@ -15284,8 +15290,8 @@ UnOp->getOperatorLoc(), false, CurFPFeatureOverrides()); } } - Expr *SubExpr = FixOverloadedFunctionReference(UnOp->getSubExpr(), - Found, Fn); + Expr *SubExpr = + FixOverloadedFunctionReference(UnOp->getSubExpr(), Found, Fn, Deduced); if (SubExpr == UnOp->getSubExpr()) return UnOp; @@ -15370,10 +15376,11 @@ llvm_unreachable("Invalid reference to overloaded function"); } -ExprResult Sema::FixOverloadedFunctionReference(ExprResult E, - DeclAccessPair Found, - FunctionDecl *Fn) { - return FixOverloadedFunctionReference(E.get(), Found, Fn); +ExprResult +Sema::FixOverloadedFunctionReference(ExprResult E, DeclAccessPair Found, + FunctionDecl *Fn, + const TemplateArgumentList *Deduced) { + return FixOverloadedFunctionReference(E.get(), Found, Fn, Deduced); } bool clang::shouldEnforceArgLimit(bool PartialOverloading, diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -7475,7 +7475,7 @@ if (DiagnoseUseOfDecl(Fn, Arg->getBeginLoc())) return ExprError(); - Arg = FixOverloadedFunctionReference(Arg, FoundResult, Fn); + Arg = FixOverloadedFunctionReference(Arg, FoundResult, Fn, nullptr); ArgType = Arg->getType(); } else return ExprError(); @@ -7527,7 +7527,7 @@ if (DiagnoseUseOfDecl(Fn, Arg->getBeginLoc())) return ExprError(); - Arg = FixOverloadedFunctionReference(Arg, FoundResult, Fn); + Arg = FixOverloadedFunctionReference(Arg, FoundResult, Fn, nullptr); ArgType = Arg->getType(); } else return ExprError(); diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -3740,6 +3740,11 @@ if (R.IsAddressOfOperand) TDF |= TDF_IgnoreQualifiers; + // Gather the explicit template arguments, if any. + TemplateArgumentListInfo ExplicitTemplateArgs; + if (Ovl->hasExplicitTemplateArgs()) + Ovl->copyTemplateArgumentsInto(ExplicitTemplateArgs); + // C++0x [temp.deduct.call]p6: // When P is a function type, pointer to function type, or pointer // to member function type: @@ -3749,8 +3754,9 @@ !ParamType->isMemberFunctionPointerType()) { if (Ovl->hasExplicitTemplateArgs()) { // But we can still look for an explicit specialization. - if (FunctionDecl *ExplicitSpec - = S.ResolveSingleFunctionTemplateSpecialization(Ovl)) + if (FunctionDecl *ExplicitSpec = + S.ResolveSingleFunctionTemplateSpecialization( + Ovl, ExplicitTemplateArgs)) return GetTypeOfFunction(S, R, ExplicitSpec); } @@ -3762,10 +3768,6 @@ return {}; } - // Gather the explicit template arguments, if any. - TemplateArgumentListInfo ExplicitTemplateArgs; - if (Ovl->hasExplicitTemplateArgs()) - Ovl->copyTemplateArgumentsInto(ExplicitTemplateArgs); QualType Match; for (UnresolvedSetIterator I = Ovl->decls_begin(), E = Ovl->decls_end(); I != E; ++I) { diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -8847,6 +8847,15 @@ TemplArgs.push_back(readTemplateArgument(Canonicalize)); } +const TemplateArgumentList * +ASTRecordReader::readTemplateArgumentList(bool Canonicalize) { + SmallVector Args; + readTemplateArgumentList(Args, Canonicalize); + if (Args.size() == 0) + return nullptr; + return TemplateArgumentList::CreateCopy(getContext(), Args); +} + /// Read a UnresolvedSet structure. void ASTRecordReader::readUnresolvedSet(LazyASTUnresolvedSet &Set) { unsigned NumDecls = readInt(); diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -1027,6 +1027,7 @@ E->MemberExprBits.HadMultipleCandidates = Record.readInt(); E->MemberExprBits.NonOdrUseReason = Record.readInt(); E->MemberExprBits.OperatorLoc = Record.readSourceLocation(); + E->Deduced = Record.readTemplateArgumentList(); if (HasQualifier || HasFoundDecl) { DeclAccessPair FoundDecl; diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -911,6 +911,10 @@ Record.push_back(E->hadMultipleCandidates()); Record.push_back(E->isNonOdrUse()); Record.AddSourceLocation(E->getOperatorLoc()); + if (E->Deduced) + Record.AddTemplateArgumentList(E->Deduced); + else + Record.push_back(0); if (HasFoundDecl) { DeclAccessPair FoundDecl = E->getFoundDecl();