Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions src/exprutil.c
Original file line number Diff line number Diff line change
Expand Up @@ -17760,7 +17760,7 @@ be returned for a C mode const variable.
function-local as well). */
con_val = initializer_constant(var);
if (con_val == NULL && gpp_mode &&
var->init_kind == (an_init_kind)initk_none &&
var->init_kind == initk_none &&
var->source_corresp.is_class_member &&
!var->is_member_constant &&
parent_class_of(var)->variant.class_struct_union.is_nonreal_class &&
Expand All @@ -17769,7 +17769,18 @@ be returned for a C mode const variable.
in-class initializer as a constant-expression during the prototype
instantiation of its class. In a real instantiation, the out-of-class
definition must be present. */
con_val = alloc_constant((a_constant_repr_kind)ck_template_param);
con_val = alloc_constant(ck_template_param);
make_template_param_expr_constant(var_rvalue_expr(var), con_val);
} else if (con_val == NULL && !constexpr_enabled && var->is_nonreal &&
var->init_kind == initk_none &&
var->template_info != NULL &&
var->template_info->template_arg_list != NULL) {
/* A variable template instance with template-dependent arguments
(e.g., "vt<T>" in a template), whose value is not known until
instantiation. A pre-C++11 constant expression (where variable
templates are an extension) requires a constant here, so treat
the reference as a template-dependent constant. */
con_val = alloc_constant(ck_template_param);
make_template_param_expr_constant(var_rvalue_expr(var), con_val);
} /* if */
if (!C_mode() && !constexpr_enabled && strict_ansi_mode &&
Expand Down
19 changes: 19 additions & 0 deletions src/pending_changes/gh-489-var-tmpl-const.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[GH #489]
Template-dependent variable template-ids in C++03 constant expressions

In C++03 GNU and Clang modes, where variable templates are accepted as an
extension, a variable template-id with template-dependent template arguments
was rejected as nonconstant where a constant expression is required (e.g., as
a template argument, an array bound, or an enumerator value). That is now
fixed. Such a reference to a constant variable template is treated as a
value-dependent constant, and its value is checked when the template is
instantiated. For example, with --g++ --c++03:

template <class T> const bool is_fp = false;
template <> const bool is_fp<float> = true;
template <bool B> struct integral_constant {
static const bool value = B;
};
template <class T>
struct is_floating_point
: integral_constant<is_fp<T> > {}; // Previously an error.
11 changes: 11 additions & 0 deletions tests/tests/regressions/.gh-489-neg.rto/default.1.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
fe_only -DTEST_NUMBER=1 --g++ --c++03 --gnu_version=150200 Test_name.c
"Test_name.c", line 13: warning: variable templates are a C++14 feature
template <class T> bool nonconst = false;
^

"Test_name.c", line 14: error: expression must have a constant value
template <class T> struct Z : integral_constant<nonconst<T> > {};
^
detected during instantiation of class "Z<T> [with T=int]" at line 15

1 error detected in the compilation of "Test_name.c".
11 changes: 11 additions & 0 deletions tests/tests/regressions/.gh-489-neg.rto/default.2.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
fe_only -DTEST_NUMBER=2 --clang --c++03 --clang_version=220100 Test_name.c
"Test_name.c", line 13: warning: variable templates are a C++14 feature
template <class T> bool nonconst = false;
^

"Test_name.c", line 14: error: expression must have a constant value
template <class T> struct Z : integral_constant<nonconst<T> > {};
^
detected during instantiation of class "Z<T> [with T=int]" at line 15

1 error detected in the compilation of "Test_name.c".
14 changes: 14 additions & 0 deletions tests/tests/regressions/.gh-489-neg.rto/default.3.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
fe_only -DTEST_NUMBER=3 --g++ --c++11 --gnu_version=150200 Test_name.c
"Test_name.c", line 13: warning: variable templates are a C++14 feature
template <class T> bool nonconst = false;
^

"Test_name.c", line 14: error: expression must have a constant value
template <class T> struct Z : integral_constant<nonconst<T> > {};
^
"Test_name.c", line 14: note: the value of variable "nonconst<int>" (declared at line 13) cannot be used as a constant
template <class T> struct Z : integral_constant<nonconst<T> > {};
^
detected during instantiation of class "Z<T> [with T=int]" at line 15

1 error detected in the compilation of "Test_name.c".
13 changes: 13 additions & 0 deletions tests/tests/regressions/.gh-489.rto/default.1.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
fe_only -DTEST_NUMBER=1 --g++ --c++03 --gnu_version=150200 Test_name.c
"Test_name.c", line 13: warning: variable templates are a C++14 feature
template <class T> inline const bool is_fp_impl = false;
^

"Test_name.c", line 14: warning: inline variables are a C++17 feature
template <> inline const bool is_fp_impl<float> = true;
^

"Test_name.c", line 25: warning: variable templates are a C++14 feature
template <int N> const bool positive = N > 0;
^

13 changes: 13 additions & 0 deletions tests/tests/regressions/.gh-489.rto/default.2.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
fe_only -DTEST_NUMBER=2 --clang --c++03 --clang_version=220100 Test_name.c
"Test_name.c", line 13: warning: variable templates are a C++14 feature
template <class T> inline const bool is_fp_impl = false;
^

"Test_name.c", line 14: warning: inline variables are a C++17 feature
template <> inline const bool is_fp_impl<float> = true;
^

"Test_name.c", line 25: warning: variable templates are a C++14 feature
template <int N> const bool positive = N > 0;
^

13 changes: 13 additions & 0 deletions tests/tests/regressions/.gh-489.rto/default.3.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
fe_only -DTEST_NUMBER=3 --g++ --c++11 --gnu_version=150200 Test_name.c
"Test_name.c", line 13: warning: variable templates are a C++14 feature
template <class T> inline const bool is_fp_impl = false;
^

"Test_name.c", line 14: warning: inline variables are a C++17 feature
template <> inline const bool is_fp_impl<float> = true;
^

"Test_name.c", line 25: warning: variable templates are a C++14 feature
template <int N> const bool positive = N > 0;
^

15 changes: 15 additions & 0 deletions tests/tests/regressions/gh-489-neg.sft.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//type:fn
//options:--g++ --c++03 --gnu_version=150200:--clang --c++03 --clang_version=220100:--g++ --c++11 --gnu_version=150200
//remark:Non-constant variable template-id rejected in a constant expression

// A variable template that is not const is still not usable where a constant
// expression is required. The error is issued when the template is
// instantiated.

template <bool B> struct integral_constant {
static const bool value = B;
};

template <class T> bool nonconst = false;
template <class T> struct Z : integral_constant<nonconst<T> > {};
Z<int> z;
41 changes: 41 additions & 0 deletions tests/tests/regressions/gh-489.sft.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//type:fp
//options:--g++ --c++03 --gnu_version=150200:--clang --c++03 --clang_version=220100:--g++ --c++11 --gnu_version=150200
//remark:Template-dependent variable template-ids in C++03 constant expressions

// In C++03 GNU and Clang modes (where variable templates are an extension),
// a variable template-id with template-dependent arguments was rejected as
// nonconstant where a constant expression is required.

template <bool B> struct integral_constant {
static const bool value = B;
};

template <class T> inline const bool is_fp_impl = false;
template <> inline const bool is_fp_impl<float> = true;
template <> inline const bool is_fp_impl<double> = true;
template <> inline const bool is_fp_impl<long double> = true;

template <class T>
struct is_floating_point : integral_constant<is_fp_impl<T> > {};

int a1[is_floating_point<float>::value ? 1 : -1];
int a2[is_floating_point<int>::value ? -1 : 1];

// Value-dependent template argument; other constant-expression contexts.
template <int N> const bool positive = N > 0;
template <int N> struct X : integral_constant<positive<N> > {
int arr[positive<N> ? 1 : 2];
enum { e = positive<N> };
};
int b1[X<1>::value ? 1 : -1];
int b2[sizeof(X<1>().arr) == sizeof(int) ? 1 : -1];
int b3[X<0>::e == 0 ? 1 : -1];

// Member variable template.
struct S {
template <class T> static const bool v = false;
};
template <> const bool S::v<float> = true;
template <class T> struct Y : integral_constant<S::v<T> > {};
int c1[Y<float>::value ? 1 : -1];
int c2[Y<int>::value ? -1 : 1];
Loading