Skip to content

Commit 03e56b5

Browse files
bors[bot]philberty
andauthored
Merge #860
860: Add overflow checking on LiteralExpression r=philberty a=philberty This checks that the literal value is within the bounds of their respective types. I have omitted 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 Co-authored-by: Philip Herron <[email protected]>
2 parents 230b55b + 507dbac commit 03e56b5

File tree

9 files changed

+278
-128
lines changed

9 files changed

+278
-128
lines changed

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

Lines changed: 207 additions & 0 deletions
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 {
@@ -886,5 +888,210 @@ CompileExpr::resolve_operator_overload (
886888
nullptr, expr.get_locus ());
887889
}
888890

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

0 commit comments

Comments
 (0)