forked from OSchip/llvm-project
Use a substituted type when determining how to substitute in non-type template
params. Don't insert addrof operations when matching against a pointer; array/function conversions should take care of this for us, assuming the argument type-checked in the first place. Add a fixme where we seem to be using a less-restrictive reference type than we should. Fixes PR 6249. llvm-svn: 95495
This commit is contained in:
parent
4692faa7a4
commit
15dda3701a
|
@ -721,11 +721,20 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E,
|
|||
if (Arg.getKind() == TemplateArgument::Declaration) {
|
||||
ValueDecl *VD = cast<ValueDecl>(Arg.getAsDecl());
|
||||
|
||||
// Find the instantiation of the template argument. This is
|
||||
// required for nested templates.
|
||||
VD = cast_or_null<ValueDecl>(
|
||||
getSema().FindInstantiatedDecl(VD, TemplateArgs));
|
||||
if (!VD)
|
||||
return SemaRef.ExprError();
|
||||
|
||||
// Derive the type we want the substituted decl to have. This had
|
||||
// better be non-dependent, or these checks will have serious problems.
|
||||
QualType TargetType = SemaRef.SubstType(NTTP->getType(), TemplateArgs,
|
||||
E->getLocation(), DeclarationName());
|
||||
assert(!TargetType.isNull() && "type substitution failed for param type");
|
||||
assert(!TargetType->isDependentType() && "param type still dependent");
|
||||
|
||||
if (VD->getDeclContext()->isRecord() &&
|
||||
(isa<CXXMethodDecl>(VD) || isa<FieldDecl>(VD))) {
|
||||
// If the value is a class member, we might have a pointer-to-member.
|
||||
|
@ -733,7 +742,7 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E,
|
|||
// pointer-to-member type. If so, we need to build an appropriate
|
||||
// expression for a pointer-to-member, since a "normal" DeclRefExpr
|
||||
// would refer to the member itself.
|
||||
if (NTTP->getType()->isMemberPointerType()) {
|
||||
if (TargetType->isMemberPointerType()) {
|
||||
QualType ClassType
|
||||
= SemaRef.Context.getTypeDeclType(
|
||||
cast<RecordDecl>(VD->getDeclContext()));
|
||||
|
@ -749,17 +758,26 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E,
|
|||
&SS);
|
||||
if (RefExpr.isInvalid())
|
||||
return SemaRef.ExprError();
|
||||
|
||||
return SemaRef.CreateBuiltinUnaryOp(E->getLocation(),
|
||||
UnaryOperator::AddrOf,
|
||||
move(RefExpr));
|
||||
|
||||
RefExpr = SemaRef.CreateBuiltinUnaryOp(E->getLocation(),
|
||||
UnaryOperator::AddrOf,
|
||||
move(RefExpr));
|
||||
assert(!RefExpr.isInvalid() &&
|
||||
SemaRef.Context.hasSameType(((Expr*) RefExpr.get())->getType(),
|
||||
TargetType));
|
||||
return move(RefExpr);
|
||||
}
|
||||
}
|
||||
if (NTTP->getType()->isPointerType()) {
|
||||
// If the template argument is expected to be a pointer
|
||||
// type, we may have to decay array/pointer references, take
|
||||
// the address of the argument, or perform cv-qualification
|
||||
// adjustments to get the type of the rvalue right. Do so.
|
||||
|
||||
if (TargetType->isPointerType()) {
|
||||
// C++03 [temp.arg.nontype]p5:
|
||||
// - For a non-type template-parameter of type pointer to
|
||||
// object, qualification conversions and the array-to-pointer
|
||||
// conversion are applied.
|
||||
// - For a non-type template-parameter of type pointer to
|
||||
// function, only the function-to-pointer conversion is
|
||||
// applied.
|
||||
|
||||
OwningExprResult RefExpr
|
||||
= SemaRef.BuildDeclRefExpr(VD, VD->getType().getNonReferenceType(),
|
||||
E->getLocation());
|
||||
|
@ -774,36 +792,15 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E,
|
|||
RefExpr = SemaRef.Owned(RefE);
|
||||
}
|
||||
|
||||
// If the unqualified types are different and a a
|
||||
// qualification conversion won't fix them types, we need to
|
||||
// take the address. FIXME: Should we encode these steps in
|
||||
// the template argument, then replay them here, like a
|
||||
// miniature InitializationSequence?
|
||||
if (!SemaRef.Context.hasSameUnqualifiedType(RefE->getType(),
|
||||
NTTP->getType()) &&
|
||||
!SemaRef.IsQualificationConversion(RefE->getType(),
|
||||
NTTP->getType())) {
|
||||
RefExpr = SemaRef.CreateBuiltinUnaryOp(E->getLocation(),
|
||||
UnaryOperator::AddrOf,
|
||||
move(RefExpr));
|
||||
if (RefExpr.isInvalid())
|
||||
return SemaRef.ExprError();
|
||||
|
||||
RefE = (Expr *)RefExpr.get();
|
||||
assert(SemaRef.Context.hasSameUnqualifiedType(RefE->getType(),
|
||||
NTTP->getType()) ||
|
||||
SemaRef.IsQualificationConversion(RefE->getType(),
|
||||
NTTP->getType()));
|
||||
}
|
||||
|
||||
// Strip top-level cv-qualifiers off the type.
|
||||
// Qualification conversions.
|
||||
RefExpr.release();
|
||||
SemaRef.ImpCastExprToType(RefE,
|
||||
NTTP->getType().getUnqualifiedType(),
|
||||
SemaRef.ImpCastExprToType(RefE, TargetType.getUnqualifiedType(),
|
||||
CastExpr::CK_NoOp);
|
||||
return SemaRef.Owned(RefE);
|
||||
}
|
||||
|
||||
// FIXME: template parameters can add qualifiers to a reference.
|
||||
|
||||
return SemaRef.BuildDeclRefExpr(VD, VD->getType().getNonReferenceType(),
|
||||
E->getLocation());
|
||||
}
|
||||
|
|
|
@ -161,3 +161,13 @@ struct X1 {
|
|||
void test_X0_X1() {
|
||||
X0<X1::pfunc> x01;
|
||||
}
|
||||
|
||||
// PR6249
|
||||
namespace pr6249 {
|
||||
template<typename T, T (*func)()> T f() {
|
||||
return func();
|
||||
}
|
||||
|
||||
int h();
|
||||
template int f<int, h>();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue