forked from OSchip/llvm-project
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. llvm-svn: 122986
This commit is contained in:
parent
b13ee84c26
commit
dd47216cc4
|
@ -1008,11 +1008,6 @@ class FunctionTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
|
|||
FunctionTypeLoc,
|
||||
FunctionType,
|
||||
FunctionLocInfo> {
|
||||
// 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<FunctionNoProtoType>(getTypePtr()))
|
||||
return 0;
|
||||
|
|
|
@ -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<QualType> &ParamTypes);
|
||||
ExprResult SubstExpr(Expr *E,
|
||||
const MultiLevelTemplateArgumentList &TemplateArgs);
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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<QualType> &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.
|
||||
///
|
||||
|
|
|
@ -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<QualType> &PTypes,
|
||||
llvm::SmallVectorImpl<ParmVarDecl*> &PVars);
|
||||
llvm::SmallVectorImpl<ParmVarDecl*> *PVars);
|
||||
|
||||
/// \brief Transforms a single function-type parameter. Return null
|
||||
/// on error.
|
||||
|
@ -3390,13 +3392,13 @@ TreeTransform<Derived>::TransformFunctionTypeParam(ParmVarDecl *OldParm) {
|
|||
|
||||
template<typename Derived>
|
||||
bool TreeTransform<Derived>::
|
||||
TransformFunctionTypeParams(FunctionProtoTypeLoc TL,
|
||||
llvm::SmallVectorImpl<QualType> &PTypes,
|
||||
llvm::SmallVectorImpl<ParmVarDecl*> &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<QualType> &OutParamTypes,
|
||||
llvm::SmallVectorImpl<ParmVarDecl*> *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<UnexpandedParameterPack, 2> Unexpanded;
|
||||
|
@ -3428,8 +3430,9 @@ bool TreeTransform<Derived>::
|
|||
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<Derived>::
|
|||
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<PackExpansionType>(OldType)) {
|
||||
|
@ -3464,7 +3468,7 @@ bool TreeTransform<Derived>::
|
|||
// 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<Derived>::
|
|||
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<Derived>::
|
|||
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<Derived>::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<Derived>::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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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<unsigned N, typename ...Types> struct get_nth_type;
|
||||
|
||||
template<unsigned N, typename Head, typename ...Tail>
|
||||
struct get_nth_type<N, Head, Tail...> : get_nth_type<N-1, Tail...> { };
|
||||
|
||||
template<typename Head, typename ...Tail>
|
||||
struct get_nth_type<0, Head, Tail...> {
|
||||
typedef Head type;
|
||||
};
|
||||
|
||||
// Placeholder type when get_nth_type fails.
|
||||
struct no_type {};
|
||||
|
||||
template<unsigned N>
|
||||
struct get_nth_type<N> {
|
||||
typedef no_type type;
|
||||
};
|
||||
|
||||
template<typename ...Args>
|
||||
typename get_nth_type<0, Args...>::type first_arg(Args...);
|
||||
|
||||
template<typename ...Args>
|
||||
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<int *>(0);
|
||||
int *ip2 = first_arg<int *, float*>(0, 0);
|
||||
float *fp1 = first_arg<float *, double*, int*>(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<int *>(0, 0);
|
||||
int *ip2 = first_arg<int *, float*>(0, 0, 0, 0);
|
||||
float *fp1 = first_arg<float *, double*, int*>(0, 0, 0);
|
||||
int i1 = second_arg<float *>(0, 0, 0);
|
||||
}
|
||||
#endif
|
||||
|
|
@ -169,7 +169,8 @@ namespace pr6249 {
|
|||
}
|
||||
|
||||
namespace PR6723 {
|
||||
template<unsigned char C> void f(int (&a)[C]); // expected-note 2{{candidate template ignored}}
|
||||
template<unsigned char C> 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}}
|
||||
|
|
Loading…
Reference in New Issue