On 12/1/20 12:38 PM, Marek Polacek wrote:
In this test, we have
static inline const int c = b;
in a class template, and we call store_init_value as usual. There, the
value is
IMPLICIT_CONV_EXPR<const float>(b)
which is is_nondependent_static_init_expression but isn't
is_nondependent_constant_expression (they only differ in STRICT).
We call fold_non_dependent_expr, but that just returns the expression
because it only instantiates is_nondependent_constant_expression
expressions. Since we're not checking the initializer of a constexpr
variable, we go on to call maybe_constant_init, whereupon we crash
because it tries to evaluate all is_nondependent_static_init_expression
expressions, which our value is, but it still contains a template code.
I think the fix is to call fold_non_dependent_init instead of
maybe_constant_init, and only call fold_non_dependent_expr on the
"this is a constexpr variable" path so as to avoid instantiating twice
in a row. Outside a template this should also avoid evaluating the
value twice.
Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk/10?
OK.
gcc/cp/ChangeLog:
PR c++/97975
* constexpr.c (fold_non_dependent_init): Add a tree parameter.
Use it.
* cp-tree.h (fold_non_dependent_init): Add a tree parameter with
a default value.
* typeck2.c (store_init_value): Call fold_non_dependent_expr
only when checking the initializer for constexpr variables.
Call fold_non_dependent_init instead of maybe_constant_init.
gcc/testsuite/ChangeLog:
PR c++/97975
* g++.dg/cpp1z/inline-var8.C: New test.
---
gcc/cp/constexpr.c | 7 ++++---
gcc/cp/cp-tree.h | 2 +-
gcc/cp/typeck2.c | 7 +++++--
gcc/testsuite/g++.dg/cpp1z/inline-var8.C | 17 +++++++++++++++++
4 files changed, 27 insertions(+), 6 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/cpp1z/inline-var8.C
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 054ee524c7a..9a1a1db1267 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -7271,7 +7271,8 @@ maybe_fold_non_dependent_expr (tree expr,
tree
fold_non_dependent_init (tree t,
tsubst_flags_t complain /*=tf_warning_or_error*/,
- bool manifestly_const_eval /*=false*/)
+ bool manifestly_const_eval /*=false*/,
+ tree object /* = NULL_TREE */)
{
if (t == NULL_TREE)
return NULL_TREE;
@@ -7279,7 +7280,7 @@ fold_non_dependent_init (tree t,
if (processing_template_decl)
{
t = fold_non_dependent_expr_template (t, complain,
- manifestly_const_eval, NULL_TREE);
+ manifestly_const_eval, object);
/* maybe_constant_init does this stripping, so do it here too. */
if (TREE_CODE (t) == TARGET_EXPR)
{
@@ -7290,7 +7291,7 @@ fold_non_dependent_init (tree t,
return t;
}
- return maybe_constant_init (t, NULL_TREE, manifestly_const_eval);
+ return maybe_constant_init (t, object, manifestly_const_eval);
}
/* Like maybe_constant_value, but returns a CONSTRUCTOR directly, rather
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 021de76e142..41516deeafa 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7953,7 +7953,7 @@ extern tree maybe_fold_non_dependent_expr (tree,
tsubst_flags_t =
tf_warning_or_error);
extern tree fold_non_dependent_init (tree,
tsubst_flags_t =
tf_warning_or_error,
- bool = false);
+ bool = false, tree =
NULL_TREE);
extern tree fold_simple (tree);
extern bool reduced_constant_expression_p (tree);
extern bool is_instantiation_of_constexpr (tree);
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index 721987e8502..575c609a365 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -744,11 +744,13 @@ store_init_value (tree decl, tree init, vec<tree,
va_gc>** cleanups, int flags)
{
bool const_init;
tree oldval = value;
- value = fold_non_dependent_expr (value, tf_warning_or_error, true, decl);
if (DECL_DECLARED_CONSTEXPR_P (decl)
|| (DECL_IN_AGGR_P (decl)
&& DECL_INITIALIZED_IN_CLASS_P (decl)))
{
+ value = fold_non_dependent_expr (value, tf_warning_or_error,
+ /*manifestly_const_eval=*/true,
+ decl);
/* Diagnose a non-constant initializer for constexpr variable or
non-inline in-class-initialized static data member. */
if (!require_constant_expression (value))
@@ -762,7 +764,8 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>**
cleanups, int flags)
value = cxx_constant_init (value, decl);
}
else
- value = maybe_constant_init (value, decl, true);
+ value = fold_non_dependent_init (value, tf_warning_or_error,
+ /*manifestly_const_eval=*/true, decl);
if (TREE_CODE (value) == CONSTRUCTOR && cp_has_mutable_p (type))
/* Poison this CONSTRUCTOR so it can't be copied to another
constexpr variable. */
diff --git a/gcc/testsuite/g++.dg/cpp1z/inline-var8.C
b/gcc/testsuite/g++.dg/cpp1z/inline-var8.C
new file mode 100644
index 00000000000..8db3c19374d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/inline-var8.C
@@ -0,0 +1,17 @@
+// PR c++/97975
+// { dg-do compile { target c++17 } }
+
+template <class>
+class A
+{
+ static const float b;
+ static inline const int c = b;
+};
+
+A<int> a;
+
+struct B
+{
+ static const float b;
+ static inline const int c = b;
+};
base-commit: 855bb43f6d0bee5a74b5d3739456ca34b4609a50