From: Douglas Gregor Date: Fri, 7 Jan 2011 00:20:55 +0000 (+0000) Subject: Factor out the template transformation of a sequence of function X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=a009b59fc2c550a229b9146aabda8e33fe3a7771;p=clang Factor out the template transformation of a sequence of function parameters into parameter types, so that substitution of explicitly-specified function template arguments uses the same path. This enables the use of explicitly-specified function template arguments with variadic templates. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@122986 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h index c5497b8149..16a8cb40c8 100644 --- a/include/clang/AST/TypeLoc.h +++ b/include/clang/AST/TypeLoc.h @@ -1008,11 +1008,6 @@ class FunctionTypeLoc : public ConcreteTypeLoc { - // ParmVarDecls* are stored after Info, one for each argument. - ParmVarDecl **getParmArray() const { - return (ParmVarDecl**) getExtraLocalData(); - } - public: SourceLocation getLParenLoc() const { return getLocalData()->LParenLoc; @@ -1035,6 +1030,11 @@ public: getLocalData()->TrailingReturn = Trailing; } + // ParmVarDecls* are stored after Info, one for each argument. + ParmVarDecl **getParmArray() const { + return (ParmVarDecl**) getExtraLocalData(); + } + unsigned getNumArgs() const { if (isa(getTypePtr())) return 0; diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index ca169f04b5..101cf6acc2 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -3890,6 +3890,10 @@ public: DeclarationName Entity); ParmVarDecl *SubstParmVarDecl(ParmVarDecl *D, const MultiLevelTemplateArgumentList &TemplateArgs); + bool SubstParmTypes(SourceLocation Loc, + ParmVarDecl **Params, unsigned NumParams, + const MultiLevelTemplateArgumentList &TemplateArgs, + llvm::SmallVectorImpl &ParamTypes); ExprResult SubstExpr(Expr *E, const MultiLevelTemplateArgumentList &TemplateArgs); diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index fcc73b8974..644ff35c3e 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -1889,19 +1889,11 @@ Sema::SubstituteExplicitTemplateArguments( // Instantiate the types of each of the function parameters given the // explicitly-specified template arguments. - for (FunctionDecl::param_iterator P = Function->param_begin(), - PEnd = Function->param_end(); - P != PEnd; - ++P) { - QualType ParamType - = SubstType((*P)->getType(), - MultiLevelTemplateArgumentList(*ExplicitArgumentList), - (*P)->getLocation(), (*P)->getDeclName()); - if (ParamType.isNull() || Trap.hasErrorOccurred()) - return TDK_SubstitutionFailure; - - ParamTypes.push_back(ParamType); - } + if (SubstParmTypes(Function->getLocation(), + Function->param_begin(), Function->getNumParams(), + MultiLevelTemplateArgumentList(*ExplicitArgumentList), + ParamTypes)) + return TDK_SubstitutionFailure; // If the caller wants a full function type back, instantiate the return // type and form that function type. diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 7deb7cad3b..c4f91f9ff6 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -1221,6 +1221,23 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm, return NewParm; } +/// \brief Substitute the given template arguments into the given set of +/// parameters, producing the set of parameter types that would be generated +/// from such a substitution. +bool Sema::SubstParmTypes(SourceLocation Loc, + ParmVarDecl **Params, unsigned NumParams, + const MultiLevelTemplateArgumentList &TemplateArgs, + llvm::SmallVectorImpl &ParamTypes) { + assert(!ActiveTemplateInstantiations.empty() && + "Cannot perform an instantiation without some context on the " + "instantiation stack"); + + TemplateInstantiator Instantiator(*this, TemplateArgs, Loc, + DeclarationName()); + return Instantiator.TransformFunctionTypeParams(Loc, Params, NumParams, 0, + ParamTypes, 0); +} + /// \brief Perform substitution on the base class specifiers of the /// given class template specialization. /// diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 25ead7bba5..60ec950c12 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -439,9 +439,11 @@ public: /// variables vector are acceptable. /// /// Return true on error. - bool TransformFunctionTypeParams(FunctionProtoTypeLoc TL, + bool TransformFunctionTypeParams(SourceLocation Loc, + ParmVarDecl **Params, unsigned NumParams, + const QualType *ParamTypes, llvm::SmallVectorImpl &PTypes, - llvm::SmallVectorImpl &PVars); + llvm::SmallVectorImpl *PVars); /// \brief Transforms a single function-type parameter. Return null /// on error. @@ -3390,13 +3392,13 @@ TreeTransform::TransformFunctionTypeParam(ParmVarDecl *OldParm) { template bool TreeTransform:: - TransformFunctionTypeParams(FunctionProtoTypeLoc TL, - llvm::SmallVectorImpl &PTypes, - llvm::SmallVectorImpl &PVars) { - FunctionProtoType *T = TL.getTypePtr(); - - for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) { - if (ParmVarDecl *OldParm = TL.getArg(i)) { + TransformFunctionTypeParams(SourceLocation Loc, + ParmVarDecl **Params, unsigned NumParams, + const QualType *ParamTypes, + llvm::SmallVectorImpl &OutParamTypes, + llvm::SmallVectorImpl *PVars) { + for (unsigned i = 0; i != NumParams; ++i) { + if (ParmVarDecl *OldParm = Params[i]) { if (OldParm->isParameterPack()) { // We have a function parameter pack that may need to be expanded. llvm::SmallVector Unexpanded; @@ -3428,8 +3430,9 @@ bool TreeTransform:: if (!NewParm) return true; - PTypes.push_back(NewParm->getType()); - PVars.push_back(NewParm); + OutParamTypes.push_back(NewParm->getType()); + if (PVars) + PVars->push_back(NewParm); } // We're done with the pack expansion. @@ -3445,14 +3448,15 @@ bool TreeTransform:: if (!NewParm) return true; - PTypes.push_back(NewParm->getType()); - PVars.push_back(NewParm); + OutParamTypes.push_back(NewParm->getType()); + if (PVars) + PVars->push_back(NewParm); continue; } // Deal with the possibility that we don't have a parameter // declaration for this parameter. - QualType OldType = T->getArgType(i); + QualType OldType = ParamTypes[i]; bool IsPackExpansion = false; if (const PackExpansionType *Expansion = dyn_cast(OldType)) { @@ -3464,7 +3468,7 @@ bool TreeTransform:: // Determine whether we should expand the parameter packs. bool ShouldExpand = false; unsigned NumExpansions = 0; - if (getDerived().TryExpandParameterPacks(TL.getBeginLoc(), SourceRange(), + if (getDerived().TryExpandParameterPacks(Loc, SourceRange(), Unexpanded.data(), Unexpanded.size(), ShouldExpand, NumExpansions)) { @@ -3480,8 +3484,9 @@ bool TreeTransform:: if (NewType.isNull()) return true; - PTypes.push_back(NewType); - PVars.push_back(0); + OutParamTypes.push_back(NewType); + if (PVars) + PVars->push_back(0); } // We're done with the pack expansion. @@ -3502,8 +3507,9 @@ bool TreeTransform:: if (IsPackExpansion) NewType = getSema().Context.getPackExpansionType(NewType); - PTypes.push_back(NewType); - PVars.push_back(0); + OutParamTypes.push_back(NewType); + if (PVars) + PVars->push_back(0); } return false; @@ -3530,7 +3536,11 @@ TreeTransform::TransformFunctionProtoType(TypeLocBuilder &TLB, QualType ResultType; if (TL.getTrailingReturn()) { - if (getDerived().TransformFunctionTypeParams(TL, ParamTypes, ParamDecls)) + if (getDerived().TransformFunctionTypeParams(TL.getBeginLoc(), + TL.getParmArray(), + TL.getNumArgs(), + TL.getTypePtr()->arg_type_begin(), + ParamTypes, &ParamDecls)) return QualType(); ResultType = getDerived().TransformType(TLB, TL.getResultLoc()); @@ -3542,7 +3552,11 @@ TreeTransform::TransformFunctionProtoType(TypeLocBuilder &TLB, if (ResultType.isNull()) return QualType(); - if (getDerived().TransformFunctionTypeParams(TL, ParamTypes, ParamDecls)) + if (getDerived().TransformFunctionTypeParams(TL.getBeginLoc(), + TL.getParmArray(), + TL.getNumArgs(), + TL.getTypePtr()->arg_type_begin(), + ParamTypes, &ParamDecls)) return QualType(); } diff --git a/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p9-0x.cpp b/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p9-0x.cpp new file mode 100644 index 0000000000..ddee152e69 --- /dev/null +++ b/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p9-0x.cpp @@ -0,0 +1,47 @@ +// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s + +// Metafunction to extract the Nth type from a set of types. +template struct get_nth_type; + +template +struct get_nth_type : get_nth_type { }; + +template +struct get_nth_type<0, Head, Tail...> { + typedef Head type; +}; + +// Placeholder type when get_nth_type fails. +struct no_type {}; + +template +struct get_nth_type { + typedef no_type type; +}; + +template +typename get_nth_type<0, Args...>::type first_arg(Args...); + +template +typename get_nth_type<1, Args...>::type second_arg(Args...); + +// Test explicit specification of function template arguments. +void test_explicit_spec_simple() { + int *ip1 = first_arg(0); + int *ip2 = first_arg(0, 0); + float *fp1 = first_arg(0, 0, 0); +} + +// Template argument deduction can extend the sequence of template +// arguments corresponding to a template parameter pack, even when the +// sequence contains explicitly specified template arguments. +// FIXME: Actually test what this paragraph specifies. +#if 0 +void test_explicit_spec_extension() { + int *ip1 = first_arg(0, 0); + int *ip2 = first_arg(0, 0, 0, 0); + float *fp1 = first_arg(0, 0, 0); + int i1 = second_arg(0, 0, 0); +} +#endif + diff --git a/test/SemaTemplate/temp_arg_nontype.cpp b/test/SemaTemplate/temp_arg_nontype.cpp index e216ad110e..b5e382c93e 100644 --- a/test/SemaTemplate/temp_arg_nontype.cpp +++ b/test/SemaTemplate/temp_arg_nontype.cpp @@ -169,7 +169,8 @@ namespace pr6249 { } namespace PR6723 { - template void f(int (&a)[C]); // expected-note 2{{candidate template ignored}} + template void f(int (&a)[C]); // expected-note {{candidate template ignored}} \ + // expected-note{{candidate function [with C = 0] not viable: no known conversion from 'int [512]' to 'int (&)[0]' for 1st argument}} void g() { int arr512[512]; f(arr512); // expected-error{{no matching function for call}}