[C++] Fix ICE with label difference as template non-type argument (PR c++/79650)

Message ID 20171213222154.GN2353@tucnak
State New
Headers show
Series
  • [C++] Fix ICE with label difference as template non-type argument (PR c++/79650)
Related show

Commit Message

Jakub Jelinek Dec. 13, 2017, 10:21 p.m.
Hi!

reduced_constant_expression_p uses initializer_constant_valid_p
to determine what is a valid constant expression.  That accepts several
cases which aren't compile time INTEGER_CST, just something that the assembler
can finalize into a constant, e.g. difference of labels, difference of
STRING_CSTs, something plus ADDR_EXPR of a static var etc.
But for template non-type arguments my understanding is we really need
an INTEGER_CST, we cam hardly instantiate on something that only during
assembly will become a constant.

The following patch attempts to diagnose it.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

Or do you have better suggestions for the diagnostics wording?

2017-12-13  Jakub Jelinek  <jakub@redhat.com>

	PR c++/79650
	* pt.c (convert_nontype_argument): Diagnose
	reduced_constant_expression_p expressions that aren't INTEGER_CST.

	* g++.dg/template/pr79650.C: New test.


	Jakub

Comments

Jason Merrill Dec. 13, 2017, 10:28 p.m. | #1
OK.

On Wed, Dec 13, 2017 at 5:21 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> Hi!

>

> reduced_constant_expression_p uses initializer_constant_valid_p

> to determine what is a valid constant expression.  That accepts several

> cases which aren't compile time INTEGER_CST, just something that the assembler

> can finalize into a constant, e.g. difference of labels, difference of

> STRING_CSTs, something plus ADDR_EXPR of a static var etc.

> But for template non-type arguments my understanding is we really need

> an INTEGER_CST, we cam hardly instantiate on something that only during

> assembly will become a constant.

>

> The following patch attempts to diagnose it.

>

> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

>

> Or do you have better suggestions for the diagnostics wording?

>

> 2017-12-13  Jakub Jelinek  <jakub@redhat.com>

>

>         PR c++/79650

>         * pt.c (convert_nontype_argument): Diagnose

>         reduced_constant_expression_p expressions that aren't INTEGER_CST.

>

>         * g++.dg/template/pr79650.C: New test.

>

> --- gcc/cp/pt.c.jj      2017-12-13 15:52:51.000000000 +0100

> +++ gcc/cp/pt.c 2017-12-13 19:21:35.861825357 +0100

> @@ -6577,7 +6577,19 @@ convert_nontype_argument (tree type, tre

>                 return NULL_TREE;

>               /* else cxx_constant_value complained but gave us

>                  a real constant, so go ahead.  */

> -             gcc_assert (TREE_CODE (expr) == INTEGER_CST);

> +             if (TREE_CODE (expr) != INTEGER_CST)

> +               {

> +                 /* Some assemble time constant expressions like

> +                    (intptr_t)&&lab1 - (intptr_t)&&lab2 or

> +                    4 + (intptr_t)&&var satisfy reduced_constant_expression_p

> +                    as we can emit them into .rodata initializers of

> +                    variables, yet they can't fold into an INTEGER_CST at

> +                    compile time.  Refuse them here.  */

> +                 gcc_checking_assert (reduced_constant_expression_p (expr));

> +                 error_at (loc, "template argument %qE for type %qT not "

> +                                "a constant integer", expr, type);

> +                 return NULL_TREE;

> +               }

>             }

>           else

>             return NULL_TREE;

> --- gcc/testsuite/g++.dg/template/pr79650.C.jj  2017-12-13 19:29:04.549196268 +0100

> +++ gcc/testsuite/g++.dg/template/pr79650.C     2017-12-13 19:34:15.202298913 +0100

> @@ -0,0 +1,20 @@

> +// PR c++/79650

> +// { dg-do compile { target c++11 } }

> +// { dg-options "" }

> +

> +typedef __INTPTR_TYPE__ intptr_t;

> +template<intptr_t> struct A {};

> +

> +void

> +foo ()

> +{

> +  static int a, b;

> +lab1:

> +lab2:

> +  A<(intptr_t)&&lab1 - (__INTPTR_TYPE__)&&lab2> c;     // { dg-error "not a constant integer" }

> +  A<(intptr_t)&&lab1 - (__INTPTR_TYPE__)&&lab1> d;

> +  A<(intptr_t)&a - (intptr_t)&b> e;                    // { dg-error "is not a constant expression" }

> +  A<(intptr_t)&a - (intptr_t)&a> f;

> +  A<(intptr_t)sizeof(a) + (intptr_t)&a> g;             // { dg-error "not a constant integer" }

> +  A<(intptr_t)&a> h;                                   // { dg-error "conversion from pointer type" }

> +}

>

>         Jakub

Patch

--- gcc/cp/pt.c.jj	2017-12-13 15:52:51.000000000 +0100
+++ gcc/cp/pt.c	2017-12-13 19:21:35.861825357 +0100
@@ -6577,7 +6577,19 @@  convert_nontype_argument (tree type, tre
 		return NULL_TREE;
 	      /* else cxx_constant_value complained but gave us
 		 a real constant, so go ahead.  */
-	      gcc_assert (TREE_CODE (expr) == INTEGER_CST);
+	      if (TREE_CODE (expr) != INTEGER_CST)
+		{
+		  /* Some assemble time constant expressions like
+		     (intptr_t)&&lab1 - (intptr_t)&&lab2 or
+		     4 + (intptr_t)&&var satisfy reduced_constant_expression_p
+		     as we can emit them into .rodata initializers of
+		     variables, yet they can't fold into an INTEGER_CST at
+		     compile time.  Refuse them here.  */
+		  gcc_checking_assert (reduced_constant_expression_p (expr));
+		  error_at (loc, "template argument %qE for type %qT not "
+				 "a constant integer", expr, type);
+		  return NULL_TREE;
+		}
 	    }
 	  else
 	    return NULL_TREE;
--- gcc/testsuite/g++.dg/template/pr79650.C.jj	2017-12-13 19:29:04.549196268 +0100
+++ gcc/testsuite/g++.dg/template/pr79650.C	2017-12-13 19:34:15.202298913 +0100
@@ -0,0 +1,20 @@ 
+// PR c++/79650
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+typedef __INTPTR_TYPE__ intptr_t;
+template<intptr_t> struct A {};
+
+void
+foo ()
+{
+  static int a, b;
+lab1:
+lab2:
+  A<(intptr_t)&&lab1 - (__INTPTR_TYPE__)&&lab2> c;	// { dg-error "not a constant integer" }
+  A<(intptr_t)&&lab1 - (__INTPTR_TYPE__)&&lab1> d;
+  A<(intptr_t)&a - (intptr_t)&b> e;			// { dg-error "is not a constant expression" }
+  A<(intptr_t)&a - (intptr_t)&a> f;
+  A<(intptr_t)sizeof(a) + (intptr_t)&a> g;		// { dg-error "not a constant integer" }
+  A<(intptr_t)&a> h;					// { dg-error "conversion from pointer type" }
+}