Skip to content

Commit 4caa204

Browse files
committed
Add overflow checking on LiteralExpression
This checks that the literal value is within the bounds of their respective types. I have ommited code fixing the other issue in the bug report that overflow/max_val integers should be saturated to infinity when cast to REAL_TYPE's this seems like something we really should have documentation to reference in the code as to why this is the correct Rust behaviour. Addresses #635
1 parent 69f6be3 commit 4caa204

File tree

9 files changed

+277
-128
lines changed

9 files changed

+277
-128
lines changed

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

+206
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
#include "rust-compile-pattern.h"
2828

2929
#include "fold-const.h"
30+
#include "realmpfr.h"
31+
#include "convert.h"
3032

3133
namespace Rust {
3234
namespace Compile {
@@ -893,5 +895,209 @@ CompileExpr::resolve_operator_overload (
893895
nullptr, expr.get_locus ());
894896
}
895897

898+
tree
899+
CompileExpr::compile_bool_literal (const HIR::LiteralExpr &expr,
900+
const TyTy::BaseType *tyty)
901+
{
902+
rust_assert (expr.get_lit_type () == HIR::Literal::BOOL);
903+
904+
const auto literal_value = expr.get_literal ();
905+
bool bval = literal_value.as_string ().compare ("true") == 0;
906+
return ctx->get_backend ()->boolean_constant_expression (bval);
907+
}
908+
909+
tree
910+
CompileExpr::compile_integer_literal (const HIR::LiteralExpr &expr,
911+
const TyTy::BaseType *tyty)
912+
{
913+
rust_assert (expr.get_lit_type () == HIR::Literal::INT);
914+
const auto literal_value = expr.get_literal ();
915+
916+
tree type = TyTyResolveCompile::compile (ctx, tyty);
917+
rust_assert (TREE_CODE (type) == INTEGER_TYPE);
918+
919+
mpz_t ival;
920+
if (mpz_init_set_str (ival, literal_value.as_string ().c_str (), 10) != 0)
921+
{
922+
rust_error_at (expr.get_locus (), "bad number in literal");
923+
return error_mark_node;
924+
}
925+
926+
mpz_t type_min;
927+
mpz_t type_max;
928+
mpz_init (type_min);
929+
mpz_init (type_max);
930+
get_type_static_bounds (type, type_min, type_max);
931+
932+
if (mpz_cmp (ival, type_min) < 0 || mpz_cmp (ival, type_max) > 0)
933+
{
934+
rust_error_at (expr.get_locus (),
935+
"integer overflows the respective type %<%s%>",
936+
tyty->get_name ().c_str ());
937+
return error_mark_node;
938+
}
939+
return double_int_to_tree (type, mpz_get_double_int (type, ival, true));
940+
}
941+
942+
tree
943+
CompileExpr::compile_float_literal (const HIR::LiteralExpr &expr,
944+
const TyTy::BaseType *tyty)
945+
{
946+
rust_assert (expr.get_lit_type () == HIR::Literal::FLOAT);
947+
const auto literal_value = expr.get_literal ();
948+
949+
mpfr_t fval;
950+
if (mpfr_init_set_str (fval, literal_value.as_string ().c_str (), 10,
951+
MPFR_RNDN)
952+
!= 0)
953+
{
954+
rust_error_at (expr.get_locus (), "bad number in literal");
955+
return error_mark_node;
956+
}
957+
958+
tree type = TyTyResolveCompile::compile (ctx, tyty);
959+
960+
REAL_VALUE_TYPE r1;
961+
real_from_mpfr (&r1, fval, type, GMP_RNDN);
962+
REAL_VALUE_TYPE r2;
963+
real_convert (&r2, TYPE_MODE (type), &r1);
964+
965+
// FIXME this probably doesn't work the real_convert function is going into
966+
// overflow mode and converting the real value into INF and there does not
967+
// seem to be any other flag to detect this
968+
bool real_value_overflow = r2.cl == rvc_inf;
969+
tree real_value = build_real (type, r2);
970+
if (TREE_OVERFLOW (real_value) || real_value_overflow)
971+
{
972+
rust_error_at (expr.get_locus (),
973+
"decimal overflows the respective type %<%s%>",
974+
tyty->get_name ().c_str ());
975+
return error_mark_node;
976+
}
977+
978+
return real_value;
979+
}
980+
981+
tree
982+
CompileExpr::compile_char_literal (const HIR::LiteralExpr &expr,
983+
const TyTy::BaseType *tyty)
984+
{
985+
rust_assert (expr.get_lit_type () == HIR::Literal::CHAR);
986+
const auto literal_value = expr.get_literal ();
987+
988+
// FIXME needs wchar_t
989+
char c = literal_value.as_string ().c_str ()[0];
990+
return ctx->get_backend ()->wchar_constant_expression (c);
991+
}
992+
993+
tree
994+
CompileExpr::compile_byte_literal (const HIR::LiteralExpr &expr,
995+
const TyTy::BaseType *tyty)
996+
{
997+
rust_assert (expr.get_lit_type () == HIR::Literal::BYTE);
998+
const auto literal_value = expr.get_literal ();
999+
1000+
tree type = TyTyResolveCompile::compile (ctx, tyty);
1001+
char c = literal_value.as_string ().c_str ()[0];
1002+
return build_int_cst (type, c);
1003+
}
1004+
1005+
tree
1006+
CompileExpr::compile_string_literal (const HIR::LiteralExpr &expr,
1007+
const TyTy::BaseType *tyty)
1008+
{
1009+
rust_assert (expr.get_lit_type () == HIR::Literal::STRING);
1010+
const auto literal_value = expr.get_literal ();
1011+
1012+
auto base = ctx->get_backend ()->string_constant_expression (
1013+
literal_value.as_string ());
1014+
return ctx->get_backend ()->address_expression (base, expr.get_locus ());
1015+
}
1016+
1017+
tree
1018+
CompileExpr::compile_byte_string_literal (const HIR::LiteralExpr &expr,
1019+
const TyTy::BaseType *tyty)
1020+
{
1021+
rust_assert (expr.get_lit_type () == HIR::Literal::BYTE_STRING);
1022+
1023+
// the type here is &[ty; capacity]
1024+
rust_assert (tyty->get_kind () == TyTy::TypeKind::REF);
1025+
const auto ref_tyty = static_cast<const TyTy::ReferenceType *> (tyty);
1026+
auto base_tyty = ref_tyty->get_base ();
1027+
rust_assert (base_tyty->get_kind () == TyTy::TypeKind::ARRAY);
1028+
auto array_tyty = static_cast<TyTy::ArrayType *> (base_tyty);
1029+
1030+
std::string value_str = expr.get_literal ().as_string ();
1031+
std::vector<tree> vals;
1032+
std::vector<unsigned long> indexes;
1033+
for (size_t i = 0; i < value_str.size (); i++)
1034+
{
1035+
char b = value_str.at (i);
1036+
tree bb = ctx->get_backend ()->char_constant_expression (b);
1037+
vals.push_back (bb);
1038+
indexes.push_back (i);
1039+
}
1040+
1041+
tree array_type = TyTyResolveCompile::compile (ctx, array_tyty);
1042+
tree constructed
1043+
= ctx->get_backend ()->array_constructor_expression (array_type, indexes,
1044+
vals,
1045+
expr.get_locus ());
1046+
1047+
return ctx->get_backend ()->address_expression (constructed,
1048+
expr.get_locus ());
1049+
}
1050+
1051+
tree
1052+
CompileExpr::type_cast_expression (tree type_to_cast_to, tree expr_tree,
1053+
Location location)
1054+
{
1055+
if (type_to_cast_to == error_mark_node || expr_tree == error_mark_node
1056+
|| TREE_TYPE (expr_tree) == error_mark_node)
1057+
return error_mark_node;
1058+
1059+
if (ctx->get_backend ()->type_size (type_to_cast_to) == 0
1060+
|| TREE_TYPE (expr_tree) == void_type_node)
1061+
{
1062+
// Do not convert zero-sized types.
1063+
return expr_tree;
1064+
}
1065+
else if (TREE_CODE (type_to_cast_to) == INTEGER_TYPE)
1066+
{
1067+
tree cast = fold (convert_to_integer (type_to_cast_to, expr_tree));
1068+
// FIXME check for TREE_OVERFLOW?
1069+
return cast;
1070+
}
1071+
else if (TREE_CODE (type_to_cast_to) == REAL_TYPE)
1072+
{
1073+
tree cast = fold (convert_to_real (type_to_cast_to, expr_tree));
1074+
// FIXME
1075+
// We might need to check that the tree is MAX val and thusly saturate it
1076+
// to in. we can get the bounds and check the value if its >= or <= to the
1077+
// min and max bounds
1078+
//
1079+
// https://github.com/Rust-GCC/gccrs/issues/635
1080+
return cast;
1081+
}
1082+
else if (TREE_CODE (type_to_cast_to) == COMPLEX_TYPE)
1083+
{
1084+
return fold (convert_to_complex (type_to_cast_to, expr_tree));
1085+
}
1086+
else if (TREE_CODE (type_to_cast_to) == POINTER_TYPE
1087+
&& TREE_CODE (TREE_TYPE (expr_tree)) == INTEGER_TYPE)
1088+
{
1089+
return fold (convert_to_pointer (type_to_cast_to, expr_tree));
1090+
}
1091+
else if (TREE_CODE (type_to_cast_to) == RECORD_TYPE
1092+
|| TREE_CODE (type_to_cast_to) == ARRAY_TYPE)
1093+
{
1094+
return fold_build1_loc (location.gcc_location (), VIEW_CONVERT_EXPR,
1095+
type_to_cast_to, expr_tree);
1096+
}
1097+
1098+
return fold_convert_loc (location.gcc_location (), type_to_cast_to,
1099+
expr_tree);
1100+
}
1101+
8961102
} // namespace Compile
8971103
} // namespace Rust

0 commit comments

Comments
 (0)