Patchwork C++ PATCH to add build_integral_nontype_arg_conv

login
register
mail settings
Submitter Jason Merrill
Date Oct. 27, 2010, 3:59 p.m.
Message ID <4CC84C53.5030300@redhat.com>
Download mbox | patch
Permalink /patch/69370/
State New
Headers show

Comments

Jason Merrill - Oct. 27, 2010, 3:59 p.m.
14.3.2 restricts the conversions that can be performed on a non-type 
template argument to bring it to the type of the parameter.  In C++98 
this is pretty trivial, as it basically just means that the original 
argument needs to be integral, but in C++0x we can use a constexpr 
conversion function to convert from a constant argument of literal class 
type.  So this new function implements the rules for this conversion.

This patch also improves the diagnostic on init/member1.C; now we say 
C<int>::j in the error message rather than <expression error>.

Tested x86_64-pc-linux-gnu, applied to trunk.

Patch

commit 0ff4fb22ceeccec01a08fd768f9f5710a7c124d2
Author: Jason Merrill <jason@redhat.com>
Date:   Tue Oct 26 21:37:07 2010 -0400

    	* call.c (build_integral_nontype_arg_conv): New.
    	* cp-tree.h: Declare it.
    	* pt.c (convert_nontype_argument): Use it.

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 1831718..204fda5 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -3165,6 +3165,76 @@  build_user_type_conversion (tree totype, tree expr, int flags)
   return NULL_TREE;
 }
 
+/* Subroutine of convert_nontype_argument.
+
+   EXPR is an argument for a template non-type parameter of integral or
+   enumeration type.  Do any necessary conversions (that are permitted for
+   non-type arguments) to convert it to the parameter type.
+
+   If conversion is successful, returns the converted expression;
+   otherwise, returns error_mark_node.  */
+
+tree
+build_integral_nontype_arg_conv (tree type, tree expr, tsubst_flags_t complain)
+{
+  conversion *conv;
+  void *p;
+  tree t;
+
+  if (error_operand_p (expr))
+    return error_mark_node;
+
+  gcc_assert (INTEGRAL_OR_ENUMERATION_TYPE_P (type));
+
+  /* Get the high-water mark for the CONVERSION_OBSTACK.  */
+  p = conversion_obstack_alloc (0);
+
+  conv = implicit_conversion (type, TREE_TYPE (expr), expr,
+			      /*c_cast_p=*/false,
+			      LOOKUP_IMPLICIT);
+
+  /* for a non-type template-parameter of integral or
+     enumeration type, integral promotions (4.5) and integral
+     conversions (4.7) are applied.  */
+  /* It should be sufficient to check the outermost conversion step, since
+     there are no qualification conversions to integer type.  */
+  if (conv)
+    switch (conv->kind)
+      {
+	/* A conversion function is OK.  If it isn't constexpr, we'll
+	   complain later that the argument isn't constant.  */
+      case ck_user:
+	/* The lvalue-to-rvalue conversion is OK.  */
+      case ck_rvalue:
+      case ck_identity:
+	break;
+
+      case ck_std:
+	t = conv->u.next->type;
+	if (INTEGRAL_OR_ENUMERATION_TYPE_P (t))
+	  break;
+
+	if (complain & tf_error)
+	  error ("conversion from %qT to %qT not considered for "
+		 "non-type template argument", t, type);
+	/* and fall through.  */
+
+      default:
+	conv = NULL;
+	break;
+      }
+
+  if (conv)
+    expr = convert_like (conv, expr, complain);
+  else
+    expr = error_mark_node;
+
+  /* Free all the conversions we allocated.  */
+  obstack_free (&conversion_obstack, p);
+
+  return expr;
+}
+
 /* Do any initial processing on the arguments to a function call.  */
 
 static VEC(tree,gc) *
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 05282ba..ec026a4 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -4651,6 +4651,7 @@  extern tree strip_top_quals			(tree);
 extern bool reference_related_p			(tree, tree);
 extern tree perform_implicit_conversion		(tree, tree, tsubst_flags_t);
 extern tree perform_implicit_conversion_flags	(tree, tree, tsubst_flags_t, int);
+extern tree build_integral_nontype_arg_conv	(tree, tree, tsubst_flags_t);
 extern tree perform_direct_initialization_if_possible (tree, tree, bool,
                                                        tsubst_flags_t);
 extern tree in_charge_arg_for_name		(tree);
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 1de5d55..8a6d451 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -5069,10 +5069,17 @@  convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
      (_conv.integral_) are applied.  */
   if (INTEGRAL_OR_ENUMERATION_TYPE_P (type))
     {
-      if (!INTEGRAL_OR_ENUMERATION_TYPE_P (expr_type))
+      tree t = build_integral_nontype_arg_conv (type, expr, complain);
+      t = fold_decl_constant_value (t);
+      if (t != error_mark_node)
+	expr = t;
+
+      if (!same_type_ignoring_top_level_qualifiers_p (type, TREE_TYPE (expr)))
 	return error_mark_node;
 
-      expr = fold_decl_constant_value (expr);
+      /* Conversion was allowed: fold it to a bare integer constant.  */
+      expr = fold (expr);
+
       /* Notice that there are constant expressions like '4 % 0' which
 	 do not fold into integer constants.  */
       if (TREE_CODE (expr) != INTEGER_CST)
@@ -5082,16 +5089,6 @@  convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
 		   "because it is a non-constant expression", expr, type);
 	  return NULL_TREE;
 	}
-
-      /* At this point, an implicit conversion does what we want,
-	 because we already know that the expression is of integral
-	 type.  */
-      expr = perform_implicit_conversion (type, expr, complain);
-      if (expr == error_mark_node)
-	return error_mark_node;
-
-      /* Conversion was allowed: fold it to a bare integer constant.  */
-      expr = fold (expr);
     }
   /* [temp.arg.nontype]/5, bullet 2