[cfe-commits] r95495 - in /cfe/trunk: lib/Sema/SemaTemplateInstantiate.cpp test/SemaTemplate/temp_arg_nontype.cpp
John McCall
rjmccall at apple.com
Sat Feb 6 02:23:55 PST 2010
Author: rjmccall
Date: Sat Feb 6 04:23:53 2010
New Revision: 95495
URL: http://llvm.org/viewvc/llvm-project?rev=95495&view=rev
Log:
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.
Modified:
cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp
Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=95495&r1=95494&r2=95495&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Sat Feb 6 04:23:53 2010
@@ -721,11 +721,20 @@
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 @@
// 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 @@
&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 @@
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());
}
Modified: cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp?rev=95495&r1=95494&r2=95495&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp (original)
+++ cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp Sat Feb 6 04:23:53 2010
@@ -161,3 +161,13 @@
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>();
+}
More information about the cfe-commits
mailing list