From: John McCall Date: Sat, 6 Feb 2010 10:23:53 +0000 (+0000) Subject: Use a substituted type when determining how to substitute in non-type template X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=645cf44cc34371c808743e5e7c19bb41ff593ca0;p=clang 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 --- 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(Arg.getAsDecl()); + // Find the instantiation of the template argument. This is + // required for nested templates. VD = cast_or_null( 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(VD) || isa(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(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()); } diff --git a/test/SemaTemplate/temp_arg_nontype.cpp b/test/SemaTemplate/temp_arg_nontype.cpp index 497bc6daf8..fdfd4e47b2 100644 --- a/test/SemaTemplate/temp_arg_nontype.cpp +++ b/test/SemaTemplate/temp_arg_nontype.cpp @@ -161,3 +161,13 @@ struct X1 { void test_X0_X1() { X0 x01; } + +// PR6249 +namespace pr6249 { + template T f() { + return func(); + } + + int h(); + template int f(); +}