[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