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 <ja...@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