aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaTemplateInstantiate.cpp
diff options
context:
space:
mode:
authorJohn McCall <rjmccall@apple.com>2010-02-06 10:23:53 +0000
committerJohn McCall <rjmccall@apple.com>2010-02-06 10:23:53 +0000
commit645cf44cc34371c808743e5e7c19bb41ff593ca0 (patch)
treea6aac211a6ef7f6b01b6b6b4484b27e4075d0769 /lib/Sema/SemaTemplateInstantiate.cpp
parentb372f51166bdf7e2951ef4820941ec3523086865 (diff)
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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@95495 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaTemplateInstantiate.cpp')
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp67
1 files changed, 32 insertions, 35 deletions
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index e17753157c..25610e4454 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -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());
}