Patchwork C++ PATCH to implement SFINAE for non-constant template arguments

login
register
mail settings
Submitter Jason Merrill
Date Sept. 6, 2010, 4:41 a.m.
Message ID <4C847116.3000507@redhat.com>
Download mbox | patch
Permalink /patch/63872/
State New
Headers show

Comments

Jason Merrill - Sept. 6, 2010, 4:41 a.m.
In certain cases, an expression that seems like an integer constant 
expression turns out not to have a constant value; in the deduction 
context such a template argument should cause deduction to fail, not 
give an error.

Tested x86_64-pc-linux-gnu, applied to trunk.
Jakub Jelinek - Jan. 20, 2011, 12:24 p.m.
On Thu, Jan 20, 2011 at 01:16:03PM +0100, Ulrich Weigand wrote:
> Jason Merrill wrote:
> 
> > --- a/gcc/testsuite/g++.dg/template/char1.C
> > +++ b/gcc/testsuite/g++.dg/template/char1.C
> > @@ -1,4 +1,4 @@
> >  template <class CharType, CharType line_terminator = 0>
> >  class String {};
> >  
> > -String<char, 255> s;
> > +String<char, 255> s;		// { dg-warning "overflow" }
> 
> It seems this causes the test to fail on platforms where "char"
> is unsigned by default (e.g. spu, powerpc, s390), because there
> is no warning on such platforms.
> 
> Maybe the test can be changed to use explicitly signed or
> unsigned char variants?

Or add -fsigned-char to dg-options...

	Jakub
Gabriel Dos Reis - Jan. 20, 2011, 9:04 p.m.
On Thu, Jan 20, 2011 at 1:46 PM, Ulrich Weigand <uweigand@de.ibm.com> wrote:
> Jakub Jelinek wrote:
>> On Thu, Jan 20, 2011 at 01:16:03PM +0100, Ulrich Weigand wrote:
>> > Jason Merrill wrote:
>> >
>> > > --- a/gcc/testsuite/g++.dg/template/char1.C
>> > > +++ b/gcc/testsuite/g++.dg/template/char1.C
>> > > @@ -1,4 +1,4 @@
>> > >  template <class CharType, CharType line_terminator = 0>
>> > >  class String {};
>> > >
>> > > -String<char, 255> s;
>> > > +String<char, 255> s;             // { dg-warning "overflow" }
>> >
>> > It seems this causes the test to fail on platforms where "char"
>> > is unsigned by default (e.g. spu, powerpc, s390), because there
>> > is no warning on such platforms.
>> >
>> > Maybe the test can be changed to use explicitly signed or
>> > unsigned char variants?
>>
>> Or add -fsigned-char to dg-options...
>
> You mean like so?

yes.

-- Gaby
Gabriel Dos Reis - Jan. 22, 2011, 4:23 p.m.
On Fri, Jan 21, 2011 at 6:52 AM, Ulrich Weigand <uweigand@de.ibm.com> wrote:

>> > You mean like so?
>>
>> yes.
>
> Huh, I see in the meantime Rainer Orth has checked in an alternative solution:
> http://gcc.gnu.org/ml/gcc-patches/2011-01/msg01454.html
> so I guess my patch is no longer necessary ...

yes, you are correct.  That version tests on all platforms so it is
probably better.

-- Gaby

Patch

commit 6131aca4355f7d5c383c0f29f82bc60b466ffa1f
Author: Jason Merrill <jason@redhat.com>
Date:   Mon Sep 6 00:14:05 2010 -0400

    	* pt.c (fold_non_dependent_expr_sfinae): Split out from...
    	(fold_non_dependent_expr): ...here.
    	(convert_nontype_argument): Use it.  Take complain parm.
    	Use perform_implicit_conversion	instead of ocp_convert.
    	Allow cv-qual changes.
    	(convert_template_argument): Pass complain down.
    	(tsubst_template_arg): Suppress constant expression warnings.
    	Don't fold here.

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 759e22f..eb47ac4 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -131,7 +131,7 @@  static int type_unification_real (tree, tree, tree, const tree *,
 				  unsigned int, int, unification_kind_t, int);
 static void note_template_header (int);
 static tree convert_nontype_argument_function (tree, tree);
-static tree convert_nontype_argument (tree, tree);
+static tree convert_nontype_argument (tree, tree, tsubst_flags_t);
 static tree convert_template_argument (tree, tree, tree,
 				       tsubst_flags_t, int, tree);
 static int for_each_template_parm (tree, tree_fn_t, void*,
@@ -4800,8 +4800,8 @@  redeclare_class_template (tree type, tree parms)
 /* Simplify EXPR if it is a non-dependent expression.  Returns the
    (possibly simplified) expression.  */
 
-tree
-fold_non_dependent_expr (tree expr)
+static tree
+fold_non_dependent_expr_sfinae (tree expr, tsubst_flags_t complain)
 {
   if (expr == NULL_TREE)
     return NULL_TREE;
@@ -4823,7 +4823,7 @@  fold_non_dependent_expr (tree expr)
       processing_template_decl = 0;
       expr = tsubst_copy_and_build (expr,
 				    /*args=*/NULL_TREE,
-				    tf_error,
+				    complain,
 				    /*in_decl=*/NULL_TREE,
 				    /*function_p=*/false,
 				    /*integral_constant_expression_p=*/true);
@@ -4832,6 +4832,12 @@  fold_non_dependent_expr (tree expr)
   return expr;
 }
 
+tree
+fold_non_dependent_expr (tree expr)
+{
+  return fold_non_dependent_expr_sfinae (expr, tf_error);
+}
+
 /* EXPR is an expression which is used in a constant-expression context.
    For instance, it could be a VAR_DECL with a constant initializer.
    Extract the innermost constant expression.
@@ -4960,7 +4966,7 @@  has_value_dependent_address (tree op)
    hacks can go away after we fix the double coercion problem.  */
 
 static tree
-convert_nontype_argument (tree type, tree expr)
+convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
 {
   tree expr_type;
 
@@ -4969,11 +4975,13 @@  convert_nontype_argument (tree type, tree expr)
      catch this later), but only to provide better diagnostic for this
      common user mistake. As suggested by DR 100, we do not mention
      linkage issues in the diagnostic as this is not the point.  */
+  /* FIXME we're making this OK.  */
   if (TREE_CODE (expr) == STRING_CST)
     {
-      error ("%qE is not a valid template argument for type %qT "
-	     "because string literals can never be used in this context",
-	     expr, type);
+      if (complain & tf_error)
+	error ("%qE is not a valid template argument for type %qT "
+	       "because string literals can never be used in this context",
+	       expr, type);
       return NULL_TREE;
     }
 
@@ -4992,8 +5000,8 @@  convert_nontype_argument (tree type, tree expr)
   if (TYPE_REF_OBJ_P (type)
       && has_value_dependent_address (expr))
     /* If we want the address and it's value-dependent, don't fold.  */;
-  else
-    expr = fold_non_dependent_expr (expr);
+  else if (!type_unknown_p (expr))
+    expr = fold_non_dependent_expr_sfinae (expr, complain);
   if (error_operand_p (expr))
     return error_mark_node;
   expr_type = TREE_TYPE (expr);
@@ -5061,15 +5069,16 @@  convert_nontype_argument (tree type, tree expr)
 	 do not fold into integer constants.  */
       if (TREE_CODE (expr) != INTEGER_CST)
 	{
-	  error ("%qE is not a valid template argument for type %qT "
-		 "because it is a non-constant expression", expr, type);
+	  if (complain & tf_error)
+	    error ("%qE is not a valid template argument for type %qT "
+		   "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 = ocp_convert (type, expr, CONV_IMPLICIT, LOOKUP_PROTECT);
+      expr = perform_implicit_conversion (type, expr, complain);
       if (expr == error_mark_node)
 	return error_mark_node;
 
@@ -5319,7 +5328,8 @@  convert_nontype_argument (tree type, tree expr)
 
   /* Sanity check: did we actually convert the argument to the
      right type?  */
-  gcc_assert (same_type_p (type, TREE_TYPE (expr)));
+  gcc_assert (same_type_ignoring_top_level_qualifiers_p
+	      (type, TREE_TYPE (expr)));
   return expr;
 }
 
@@ -5784,7 +5794,7 @@  convert_template_argument (tree parm,
 	   conversions can occur is part of determining which
 	   function template to call, or whether a given explicit
 	   argument specification is valid.  */
-	val = convert_nontype_argument (t, orig_arg);
+	val = convert_nontype_argument (t, orig_arg, complain);
       else
 	val = orig_arg;
 
@@ -8270,9 +8280,12 @@  tsubst_template_arg (tree t, tree args, tsubst_flags_t complain, tree in_decl)
     r = tsubst (t, args, complain, in_decl);
   else
     {
+      if (!(complain & tf_warning))
+	++c_inhibit_evaluation_warnings;
       r = tsubst_expr (t, args, complain, in_decl,
 		       /*integral_constant_expression_p=*/true);
-      r = fold_non_dependent_expr (r);
+      if (!(complain & tf_warning))
+	--c_inhibit_evaluation_warnings;
     }
   return r;
 }
diff --git a/gcc/testsuite/g++.dg/template/char1.C b/gcc/testsuite/g++.dg/template/char1.C
index 64ffda8..c440577 100644
--- a/gcc/testsuite/g++.dg/template/char1.C
+++ b/gcc/testsuite/g++.dg/template/char1.C
@@ -1,4 +1,4 @@ 
 template <class CharType, CharType line_terminator = 0>
 class String {};
 
-String<char, 255> s;
+String<char, 255> s;		// { dg-warning "overflow" }
diff --git a/gcc/testsuite/g++.dg/template/nontype10.C b/gcc/testsuite/g++.dg/template/nontype10.C
index cd3a3aa..83ac8e3 100644
--- a/gcc/testsuite/g++.dg/template/nontype10.C
+++ b/gcc/testsuite/g++.dg/template/nontype10.C
@@ -5,6 +5,6 @@ 
 template <int  T> struct A {};
 template <void* T> struct B {};
 
-A<NULL> a;
+A<NULL> a;			// { dg-warning "NULL" }
 B<NULL> b;  // { dg-error "" }
 
diff --git a/gcc/testsuite/g++.dg/template/sfinae25.C b/gcc/testsuite/g++.dg/template/sfinae25.C
new file mode 100644
index 0000000..e9ee83e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/sfinae25.C
@@ -0,0 +1,14 @@ 
+template <int I>
+struct A { };
+
+template <int J>
+void f(A<1/J>);
+
+template <int J>
+void f(...) { }
+
+int main()
+{
+  f<0>();
+}
+