diff options
author | John McCall <rjmccall@apple.com> | 2010-02-02 02:21:27 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2010-02-02 02:21:27 +0000 |
commit | c1f69989b142804eb9c4572fbde08fcc052d203c (patch) | |
tree | e14729c6ff041f1f5cd3379ac71c3a65fea81dfe /clang/lib/Sema/SemaTemplateDeduction.cpp | |
parent | 339975e5d57281eae569d5656023b5ab3b18c1e2 (diff) | |
download | bcm5719-llvm-c1f69989b142804eb9c4572fbde08fcc052d203c.tar.gz bcm5719-llvm-c1f69989b142804eb9c4572fbde08fcc052d203c.zip |
Implement C++ [temp.deduct.call]p6, template argument deduction for overloaded
arguments. Fix a bug where incomplete explicit specializations were being
passed through as legitimate. Fix a bug where the absence of an explicit
specialization in an overload set was causing overall deduction to fail.
Fixes PR6191.
llvm-svn: 95052
Diffstat (limited to 'clang/lib/Sema/SemaTemplateDeduction.cpp')
-rw-r--r-- | clang/lib/Sema/SemaTemplateDeduction.cpp | 142 |
1 files changed, 111 insertions, 31 deletions
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index b9160930cb1..de13b664fe6 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -1306,6 +1306,106 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, return TDK_Success; } +static QualType GetTypeOfFunction(ASTContext &Context, + bool isAddressOfOperand, + FunctionDecl *Fn) { + if (!isAddressOfOperand) return Fn->getType(); + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn)) + if (Method->isInstance()) + return Context.getMemberPointerType(Fn->getType(), + Context.getTypeDeclType(Method->getParent()).getTypePtr()); + return Context.getPointerType(Fn->getType()); +} + +/// Apply the deduction rules for overload sets. +/// +/// \return the null type if this argument should be treated as an +/// undeduced context +static QualType +ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams, + Expr *Arg, QualType ParamType) { + bool isAddressOfOperand = false; + + Arg = Arg->IgnoreParens(); + if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(Arg)) { + assert(UnOp->getOpcode() == UnaryOperator::AddrOf); + isAddressOfOperand = true; + Arg = UnOp->getSubExpr()->IgnoreParens(); + } + + const UnresolvedSetImpl *Decls; + bool HasExplicitArgs; + if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(Arg)) { + Decls = &ULE->getDecls(); + HasExplicitArgs = ULE->hasExplicitTemplateArgs(); + } else { + UnresolvedMemberExpr *UME = cast<UnresolvedMemberExpr>(Arg); + Decls = &UME->getDecls(); + HasExplicitArgs = ULE->hasExplicitTemplateArgs(); + } + + // If there were explicit template arguments, we can only find + // something via C++ [temp.arg.explicit]p3, i.e. if the arguments + // unambiguously name a full specialization. + if (HasExplicitArgs) { + // But we can still look for an explicit specialization. + if (FunctionDecl *ExplicitSpec + = S.ResolveSingleFunctionTemplateSpecialization(Arg)) + return GetTypeOfFunction(S.Context, isAddressOfOperand, ExplicitSpec); + return QualType(); + } + + // C++0x [temp.deduct.call]p6: + // When P is a function type, pointer to function type, or pointer + // to member function type: + + if (!ParamType->isFunctionType() && + !ParamType->isFunctionPointerType() && + !ParamType->isMemberFunctionPointerType()) + return QualType(); + + QualType Match; + for (UnresolvedSetIterator I = Decls->begin(), + E = Decls->end(); I != E; ++I) { + NamedDecl *D = (*I)->getUnderlyingDecl(); + + // - If the argument is an overload set containing one or more + // function templates, the parameter is treated as a + // non-deduced context. + if (isa<FunctionTemplateDecl>(D)) + return QualType(); + + FunctionDecl *Fn = cast<FunctionDecl>(D); + QualType ArgType = GetTypeOfFunction(S.Context, isAddressOfOperand, Fn); + + // - If the argument is an overload set (not containing function + // templates), trial argument deduction is attempted using each + // of the members of the set. If deduction succeeds for only one + // of the overload set members, that member is used as the + // argument value for the deduction. If deduction succeeds for + // more than one member of the overload set the parameter is + // treated as a non-deduced context. + + // We do all of this in a fresh context per C++0x [temp.deduct.type]p2: + // Type deduction is done independently for each P/A pair, and + // the deduced template argument values are then combined. + // So we do not reject deductions which were made elsewhere. + llvm::SmallVector<TemplateArgument, 8> Deduced(TemplateParams->size()); + Sema::TemplateDeductionInfo Info(S.Context); + unsigned TDF = 0; + + Sema::TemplateDeductionResult Result + = DeduceTemplateArguments(S.Context, TemplateParams, + ParamType, ArgType, + Info, Deduced, TDF); + if (Result) continue; + if (!Match.isNull()) return QualType(); + Match = ArgType; + } + + return Match; +} + /// \brief Perform template argument deduction from a function call /// (C++ [temp.deduct.call]). /// @@ -1384,6 +1484,15 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, QualType ParamType = ParamTypes[I]; QualType ArgType = Args[I]->getType(); + // Overload sets usually make this parameter an undeduced + // context, but there are sometimes special circumstances. + if (ArgType == Context.OverloadTy) { + ArgType = ResolveOverloadForDeduction(*this, TemplateParams, + Args[I], ParamType); + if (ArgType.isNull()) + continue; + } + // C++ [temp.deduct.call]p2: // If P is not a reference type: QualType CanonParamType = Context.getCanonicalType(ParamType); @@ -1454,36 +1563,6 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, ParamType->getAs<PointerType>()->getPointeeType()))) TDF |= TDF_DerivedClass; - // FIXME: C++0x [temp.deduct.call] paragraphs 6-9 deal with function - // pointer parameters. - - if (Context.hasSameUnqualifiedType(ArgType, Context.OverloadTy)) { - // We know that template argument deduction will fail if the argument is - // still an overloaded function. Check whether we can resolve this - // argument as a single function template specialization per - // C++ [temp.arg.explicit]p3. - FunctionDecl *ExplicitSpec - = ResolveSingleFunctionTemplateSpecialization(Args[I]); - Expr *ResolvedArg = 0; - if (ExplicitSpec) - ResolvedArg = FixOverloadedFunctionReference(Args[I], ExplicitSpec); - if (!ExplicitSpec || !ResolvedArg) { - // Template argument deduction fails if we can't resolve the overloaded - // function. - return TDK_FailedOverloadResolution; - } - - // Get the type of the resolved argument, and adjust it per - // C++0x [temp.deduct.call]p3. - ArgType = ResolvedArg->getType(); - if (!ParamWasReference && ArgType->isFunctionType()) - ArgType = Context.getPointerType(ArgType); - if (ArgType->isPointerType() || ArgType->isMemberPointerType()) - TDF |= TDF_IgnoreQualifiers; - - ResolvedArg->Destroy(Context); - } - if (TemplateDeductionResult Result = ::DeduceTemplateArguments(Context, TemplateParams, ParamType, ArgType, Info, Deduced, @@ -1548,9 +1627,10 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, // Trap any errors that might occur. SFINAETrap Trap(*this); + Deduced.resize(TemplateParams->size()); + if (!ArgFunctionType.isNull()) { // Deduce template arguments from the function type. - Deduced.resize(TemplateParams->size()); if (TemplateDeductionResult Result = ::DeduceTemplateArguments(Context, TemplateParams, FunctionType, ArgFunctionType, Info, |