A template-argument for a non-type template-parameter shall be a converted constant expression. But an lvalue-to-rvalue conversion applied to a volatile glvalue is not allowed to be part of the evaluation of a constant expression. So this test should be rejected.
The non_const_var_error tweaks are needed to give the correct diagnostic. I don't plan to backport this to older branches, unless you think otherwise. Bootstrapped/regtested on x86_64-linux, ok for trunk? 2018-12-10 Marek Polacek <pola...@redhat.com> PR c++/86608 - reading constexpr volatile variable. * constexpr.c (non_const_var_error): Add a boolean parameter. Use it. (cxx_eval_constant_expression): Adjust call to non_const_var_error. (potential_constant_expression_1): Also give error when reading a constexpr volatile variable. * g++.dg/cpp0x/constexpr-volatile2.C: New test. * g++.dg/cpp0x/pr65327.C: Add dg-error. diff --git gcc/cp/constexpr.c gcc/cp/constexpr.c index 1c844a8c2ef..e78cc4a81d6 100644 --- gcc/cp/constexpr.c +++ gcc/cp/constexpr.c @@ -3431,10 +3431,11 @@ cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t, /* Complain about R, a VAR_DECL, not being usable in a constant expression. Shared between potential_constant_expression and - cxx_eval_constant_expression. */ + cxx_eval_constant_expression. If SKIP_OWN_INIT_P is true, don't report + that R was used in its own initializer, as the problem is elsewhere. */ static void -non_const_var_error (tree r) +non_const_var_error (tree r, bool skip_own_init_p) { tree type = TREE_TYPE (r); error ("the value of %qD is not usable in a constant " @@ -3442,7 +3443,7 @@ non_const_var_error (tree r) /* Avoid error cascade. */ if (DECL_INITIAL (r) == error_mark_node) return; - if (DECL_DECLARED_CONSTEXPR_P (r)) + if (!skip_own_init_p && DECL_DECLARED_CONSTEXPR_P (r)) inform (DECL_SOURCE_LOCATION (r), "%qD used in its own initializer", r); else if (INTEGRAL_OR_ENUMERATION_TYPE_P (type)) @@ -4251,7 +4252,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, if (DECL_P (r)) { if (!ctx->quiet) - non_const_var_error (r); + non_const_var_error (r, /*skip_own_init_p=*/false); *non_constant_p = true; } break; @@ -5692,7 +5693,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, if (want_rval && !var_in_maybe_constexpr_fn (t) && !type_dependent_expression_p (t) - && !decl_maybe_constant_var_p (t) + && (!decl_maybe_constant_var_p (t) || TREE_THIS_VOLATILE (t)) && (strict || !CP_TYPE_CONST_NON_VOLATILE_P (TREE_TYPE (t)) || (DECL_INITIAL (t) @@ -5701,7 +5702,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, && !is_really_empty_class (TREE_TYPE (t))) { if (flags & tf_error) - non_const_var_error (t); + non_const_var_error (t, TREE_THIS_VOLATILE (t)); return false; } return true; diff --git gcc/testsuite/g++.dg/cpp0x/constexpr-volatile2.C gcc/testsuite/g++.dg/cpp0x/constexpr-volatile2.C new file mode 100644 index 00000000000..2054fb83768 --- /dev/null +++ gcc/testsuite/g++.dg/cpp0x/constexpr-volatile2.C @@ -0,0 +1,13 @@ +// PR c++/86608 +// { dg-do compile { target c++11 } } + +template<typename T, T v> struct X {}; + +int +main () +{ + static constexpr volatile int a = 3; + constexpr volatile int b = 2; + return (sizeof(X<decltype(a), a>) // { dg-error "not usable in a constant expression" } + + sizeof(X<decltype(b), b>)); // { dg-error "not usable in a constant expression" } +} diff --git gcc/testsuite/g++.dg/cpp0x/pr65327.C gcc/testsuite/g++.dg/cpp0x/pr65327.C index c6cefaba692..0ba189a24b8 100644 --- gcc/testsuite/g++.dg/cpp0x/pr65327.C +++ gcc/testsuite/g++.dg/cpp0x/pr65327.C @@ -15,4 +15,4 @@ constexpr volatile int bar () { return i; -} +} // { dg-error "not usable in a constant expression" }