Skip to content

Commit c3ca1b9

Browse files
committed
gccrs: Fix ICE with invalid const expression
This patch handles the overflowed var expression in the const block, so that we error properly in the const expr code. It was missing some stuff from the c++ implementation in how this should be handled properly. Fixes #4139 gcc/rust/ChangeLog: * backend/rust-compile-expr.cc (CompileExpr::compile_integer_literal): cleanup * backend/rust-constexpr.cc (struct constexpr_global_ctx): port over c++ helpers (decl_really_constant_value): likewise (eval_constant_expression): likewise (non_const_var_error): likewise gcc/testsuite/ChangeLog: * rust/compile/issue-4139.rs: New test. Signed-off-by: Philip Herron <herron.philip@googlemail.com>
1 parent b45db77 commit c3ca1b9

File tree

3 files changed

+135
-39
lines changed

3 files changed

+135
-39
lines changed

gcc/rust/backend/rust-compile-expr.cc

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1655,37 +1655,39 @@ CompileExpr::compile_integer_literal (const HIR::LiteralExpr &expr,
16551655
const TyTy::BaseType *tyty)
16561656
{
16571657
rust_assert (expr.get_lit_type () == HIR::Literal::INT);
1658-
const auto literal_value = expr.get_literal ();
1659-
1658+
const auto &literal_value = expr.get_literal ();
16601659
tree type = TyTyResolveCompile::compile (ctx, tyty);
16611660

1661+
std::string s = literal_value.as_string ();
1662+
s.erase (std::remove (s.begin (), s.end (), '_'), s.end ());
1663+
1664+
int base = 0;
16621665
mpz_t ival;
1663-
if (mpz_init_set_str (ival, literal_value.as_string ().c_str (), 10) != 0)
1666+
if (mpz_init_set_str (ival, s.c_str (), base) != 0)
16641667
{
1665-
rust_error_at (expr.get_locus (), "bad number in literal");
1668+
rust_error_at (expr.get_locus (), "failed to load number literal");
16661669
return error_mark_node;
16671670
}
1671+
if (expr.is_negative ())
1672+
mpz_neg (ival, ival);
16681673

1669-
mpz_t type_min;
1670-
mpz_t type_max;
1674+
mpz_t type_min, type_max;
16711675
mpz_init (type_min);
16721676
mpz_init (type_max);
16731677
get_type_static_bounds (type, type_min, type_max);
16741678

1675-
if (expr.is_negative ())
1676-
{
1677-
mpz_neg (ival, ival);
1678-
}
16791679
if (mpz_cmp (ival, type_min) < 0 || mpz_cmp (ival, type_max) > 0)
16801680
{
16811681
rust_error_at (expr.get_locus (),
16821682
"integer overflows the respective type %qs",
16831683
tyty->get_name ().c_str ());
1684+
mpz_clear (type_min);
1685+
mpz_clear (type_max);
1686+
mpz_clear (ival);
16841687
return error_mark_node;
16851688
}
16861689

16871690
tree result = wide_int_to_tree (type, wi::from_mpz (type, ival, true));
1688-
16891691
mpz_clear (type_min);
16901692
mpz_clear (type_max);
16911693
mpz_clear (ival);

gcc/rust/backend/rust-constexpr.cc

Lines changed: 115 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -101,12 +101,54 @@ struct constexpr_global_ctx
101101
auto_vec<tree, 16> heap_vars;
102102
/* Cleanups that need to be evaluated at the end of CLEANUP_POINT_EXPR. */
103103
vec<tree> *cleanups;
104+
/* If non-null, only allow modification of existing values of the variables
105+
in this set. Set by modifiable_tracker, below. */
106+
hash_set<tree> *modifiable;
104107
/* Number of heap VAR_DECL deallocations. */
105108
unsigned heap_dealloc_count;
106109
/* Constructor. */
107110
constexpr_global_ctx ()
108111
: constexpr_ops_count (0), cleanups (NULL), heap_dealloc_count (0)
109112
{}
113+
114+
tree get_value (tree t)
115+
{
116+
if (tree *p = values.get (t))
117+
if (*p != void_node)
118+
return *p;
119+
return NULL_TREE;
120+
}
121+
tree *get_value_ptr (tree t, bool initializing)
122+
{
123+
if (modifiable && !modifiable->contains (t))
124+
return nullptr;
125+
if (tree *p = values.get (t))
126+
{
127+
if (*p != void_node)
128+
return p;
129+
else if (initializing)
130+
{
131+
*p = NULL_TREE;
132+
return p;
133+
}
134+
}
135+
return nullptr;
136+
}
137+
void put_value (tree t, tree v)
138+
{
139+
bool already_in_map = values.put (t, v);
140+
if (!already_in_map && modifiable)
141+
modifiable->add (t);
142+
}
143+
void destroy_value (tree t)
144+
{
145+
if (TREE_CODE (t) == VAR_DECL || TREE_CODE (t) == PARM_DECL
146+
|| TREE_CODE (t) == RESULT_DECL)
147+
values.put (t, void_node);
148+
else
149+
values.remove (t);
150+
}
151+
void clear_value (tree t) { values.remove (t); }
110152
};
111153

112154
/* In constexpr.cc */
@@ -457,6 +499,7 @@ save_fundef_copy (tree fun, tree copy)
457499

458500
static tree constant_value_1 (tree decl, bool strict_p,
459501
bool return_aggregate_cst_ok_p, bool unshare_p);
502+
static tree decl_really_constant_value (tree decl, bool unshare_p /*= true*/);
460503
tree decl_constant_value (tree decl, bool unshare_p);
461504

462505
static void non_const_var_error (location_t loc, tree r);
@@ -1925,30 +1968,40 @@ eval_constant_expression (const constexpr_ctx *ctx, tree t, bool lval,
19251968
}
19261969
/* fall through */
19271970
case CONST_DECL:
1928-
{
1929-
/* We used to not check lval for CONST_DECL, but darwin.cc uses
1930-
CONST_DECL for aggregate constants. */
1931-
if (lval)
1932-
return t;
1933-
else if (t == ctx->object)
1934-
return ctx->ctor;
1935-
if (VAR_P (t))
1936-
if (tree *p = ctx->global->values.get (t))
1937-
if (*p != NULL_TREE)
1938-
{
1939-
r = *p;
1940-
break;
1941-
}
1971+
/* We used to not check lval for CONST_DECL, but darwin.cc uses
1972+
CONST_DECL for aggregate constants. */
1973+
if (lval)
1974+
return t;
1975+
else if (t == ctx->object)
1976+
return ctx->ctor;
1977+
if (VAR_P (t))
1978+
{
1979+
if (tree v = ctx->global->get_value (t))
1980+
{
1981+
r = v;
1982+
break;
1983+
}
1984+
}
1985+
if (COMPLETE_TYPE_P (TREE_TYPE (t))
1986+
&& is_really_empty_class (TREE_TYPE (t), /*ignore_vptr*/ false))
1987+
{
1988+
/* If the class is empty, we aren't actually loading anything. */
1989+
r = build_constructor (TREE_TYPE (t), NULL);
1990+
TREE_CONSTANT (r) = true;
1991+
}
1992+
else if (ctx->strict)
1993+
r = decl_really_constant_value (t, /*unshare_p=*/false);
1994+
else
19421995
r = decl_constant_value (t, /*unshare_p=*/false);
1943-
if (TREE_CODE (r) == TARGET_EXPR
1944-
&& TREE_CODE (TARGET_EXPR_INITIAL (r)) == CONSTRUCTOR)
1945-
r = TARGET_EXPR_INITIAL (r);
1946-
if (DECL_P (r))
1947-
{
1996+
if (TREE_CODE (r) == TARGET_EXPR
1997+
&& TREE_CODE (TARGET_EXPR_INITIAL (r)) == CONSTRUCTOR)
1998+
r = TARGET_EXPR_INITIAL (r);
1999+
if (DECL_P (r) && !(VAR_P (t) && TYPE_REF_P (TREE_TYPE (t))))
2000+
{
2001+
if (!ctx->quiet)
19482002
non_const_var_error (loc, r);
1949-
return r;
1950-
}
1951-
}
2003+
*non_constant_p = true;
2004+
}
19522005
break;
19532006

19542007
case PARM_DECL:
@@ -4024,6 +4077,17 @@ constant_value_1 (tree decl, bool, bool, bool unshare_p)
40244077
return unshare_p ? unshare_expr (decl) : decl;
40254078
}
40264079

4080+
/* Like scalar_constant_value, but can also return aggregate initializers.
4081+
If UNSHARE_P, return an unshared copy of the initializer. */
4082+
4083+
tree
4084+
decl_really_constant_value (tree decl, bool unshare_p /*= true*/)
4085+
{
4086+
return constant_value_1 (decl, /*strict_p=*/true,
4087+
/*return_aggregate_cst_ok_p=*/true,
4088+
/*unshare_p=*/unshare_p);
4089+
}
4090+
40274091
// A more relaxed version of decl_really_constant_value, used by the
40284092
// common C/C++ code.
40294093
tree
@@ -4037,15 +4101,38 @@ decl_constant_value (tree decl, bool unshare_p)
40374101
static void
40384102
non_const_var_error (location_t loc, tree r)
40394103
{
4040-
error_at (loc,
4041-
"the value of %qD is not usable in a constant "
4042-
"expression",
4043-
r);
4104+
tree type = TREE_TYPE (r);
4105+
40444106
/* Avoid error cascade. */
40454107
if (DECL_INITIAL (r) == error_mark_node)
40464108
return;
4047-
4048-
// more in cp/constexpr.cc
4109+
if (DECL_DECLARED_CONSTEXPR_P (r))
4110+
inform (DECL_SOURCE_LOCATION (r), "%qD used in its own initializer", r);
4111+
else if (INTEGRAL_OR_ENUMERATION_TYPE_P (type))
4112+
{
4113+
if (!DECL_INITIAL (r) || !TREE_CONSTANT (DECL_INITIAL (r))
4114+
|| !DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (r))
4115+
inform (DECL_SOURCE_LOCATION (r),
4116+
"%qD was not initialized with a constant "
4117+
"expression",
4118+
r);
4119+
else
4120+
gcc_unreachable ();
4121+
}
4122+
else if (TYPE_REF_P (type))
4123+
inform (DECL_SOURCE_LOCATION (r),
4124+
"%qD was not initialized with a constant "
4125+
"expression",
4126+
r);
4127+
else
4128+
{
4129+
if (!DECL_DECLARED_CONSTEXPR_P (r))
4130+
inform (DECL_SOURCE_LOCATION (r), "%qD was not declared %<constexpr%>",
4131+
r);
4132+
else
4133+
inform (DECL_SOURCE_LOCATION (r),
4134+
"%qD does not have integral or enumeration type", r);
4135+
}
40494136
}
40504137

40514138
static tree
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// { dg-skip-if "" { *-*-* } { "-m32" } { "" } }
2+
const X: i32 = const {
3+
let a = 0x736f6d6570736575;
4+
// { dg-error "integer overflows the respective type" "" { target *-*-* } .-1 }
5+
let b = 14;
6+
a + b
7+
};

0 commit comments

Comments
 (0)