Message ID | 20201201173820.1908090-1-polacek@redhat.com |
---|---|
State | New |
Headers | show |
Series | c++: Fix ICE with inline variable in template [PR97975] | expand |
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 >
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; +};