Skip to content

Commit bb85500

Browse files
bors[bot]philberty
andauthored
Merge #383
383: Reuse fold-const.c from GCC to enforce const array capacities r=philberty a=philberty Rust allows for constant eval for cases like array capacity, the initial version of this code forced the programmer to only use literals which was not correct but got the type system off the ground. This now takes advantage of the GCC backend object to offer 3 helprs. 1. check for constant Bexpression* are equal 2. extract a size_t constant value from the Bexpression* 3. to string the Bexpression constant We can get away with the extraction of the value here because we know its going to be a usize for array capacity but some thought is needed if these methods are to be reused in other cases. There is a new ConstFold namespace which should be extensible for const functions later on and const generics. Fixes: #296 Co-authored-by: Philip Herron <[email protected]>
2 parents dd19466 + 393b783 commit bb85500

25 files changed

+942
-149
lines changed

gcc/rust/Make-lang.in

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@ GRS_OBJS = \
7979
rust/rust-hir-type-check.o \
8080
rust/rust-tyty.o \
8181
rust/rust-tyctx.o \
82-
rust/rust-hir-liveness.o \
82+
rust/rust-hir-const-fold.o \
83+
rust/rust-hir-liveness.o \
8384
$(END)
8485
# removed object files from here
8586

gcc/rust/backend/rust-compile-context.h

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "rust-compile-tyty.h"
2828
#include "rust-ast-full.h"
2929
#include "rust-hir-full.h"
30+
#include "rust-hir-const-fold-ctx.h"
3031

3132
namespace Rust {
3233
namespace Compile {
@@ -43,7 +44,8 @@ class Context
4344
Context (::Backend *backend)
4445
: backend (backend), resolver (Resolver::Resolver::get ()),
4546
tyctx (Resolver::TypeCheckContext::get ()),
46-
mappings (Analysis::Mappings::get ())
47+
mappings (Analysis::Mappings::get ()),
48+
const_ctx (ConstFold::Context::get ())
4749
{
4850
// insert the builtins
4951
auto builtins = resolver->get_builtin_types ();
@@ -104,6 +106,7 @@ class Context
104106
Resolver::Resolver *get_resolver () { return resolver; }
105107
Resolver::TypeCheckContext *get_tyctx () { return tyctx; }
106108
Analysis::Mappings *get_mappings () { return mappings; }
109+
ConstFold::Context *get_const_ctx () { return const_ctx; }
107110

108111
void push_block (Bblock *scope)
109112
{
@@ -260,6 +263,7 @@ class Context
260263
Resolver::Resolver *resolver;
261264
Resolver::TypeCheckContext *tyctx;
262265
Analysis::Mappings *mappings;
266+
ConstFold::Context *const_ctx;
263267

264268
// state
265269
std::vector<fncontext> fn_stack;
@@ -420,16 +424,10 @@ class TyTyResolveCompile : public TyTy::TyVisitor
420424

421425
void visit (TyTy::ArrayType &type) override
422426
{
423-
mpz_t ival;
424-
mpz_init_set_ui (ival, type.get_capacity ());
425-
426-
Btype *capacity_type = ctx->get_backend ()->integer_type (true, 32);
427-
Bexpression *length
428-
= ctx->get_backend ()->integer_constant_expression (capacity_type, ival);
429-
430427
Btype *element_type
431428
= TyTyResolveCompile::compile (ctx, type.get_element_type ());
432-
translated = ctx->get_backend ()->array_type (element_type, length);
429+
translated
430+
= ctx->get_backend ()->array_type (element_type, type.get_capacity ());
433431
}
434432

435433
void visit (TyTy::BoolType &type) override

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

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,12 @@ class CompileExpr : public HIRCompileBase
275275
return;
276276
}
277277

278-
Btype *array_type = TyTyResolveCompile::compile (ctx, tyty);
278+
rust_assert (tyty->get_kind () == TyTy::TypeKind::ARRAY);
279+
TyTy::ArrayType *array_tyty = static_cast<TyTy::ArrayType *> (tyty);
280+
capacity_expr = array_tyty->get_capacity ();
281+
282+
Btype *array_type = TyTyResolveCompile::compile (ctx, array_tyty);
283+
rust_assert (array_type != nullptr);
279284

280285
expr.get_internal_elements ()->accept_vis (*this);
281286
std::vector<unsigned long> indexes;
@@ -302,7 +307,11 @@ class CompileExpr : public HIRCompileBase
302307
Bexpression *translated_expr
303308
= CompileExpr::Compile (elems.get_elem_to_copy (), ctx);
304309

305-
for (size_t i = 0; i < elems.get_num_elements (); ++i)
310+
size_t capacity;
311+
bool ok = ctx->get_backend ()->const_size_cast (capacity_expr, &capacity);
312+
rust_assert (ok);
313+
314+
for (size_t i = 0; i < capacity; ++i)
306315
constructor.push_back (translated_expr);
307316
}
308317

@@ -786,9 +795,12 @@ class CompileExpr : public HIRCompileBase
786795
}
787796

788797
private:
789-
CompileExpr (Context *ctx) : HIRCompileBase (ctx), translated (nullptr) {}
798+
CompileExpr (Context *ctx)
799+
: HIRCompileBase (ctx), translated (nullptr), capacity_expr (nullptr)
800+
{}
790801

791802
Bexpression *translated;
803+
Bexpression *capacity_expr;
792804
std::vector<Bexpression *> constructor;
793805
};
794806

gcc/rust/hir/rust-ast-lower-expr.h

Lines changed: 1 addition & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -27,42 +27,6 @@
2727
namespace Rust {
2828
namespace HIR {
2929

30-
class ArrayCapacityConstant : public ASTLoweringBase
31-
{
32-
using Rust::HIR::ASTLoweringBase::visit;
33-
34-
public:
35-
static bool fold (AST::Expr *expr, size_t *folded_result)
36-
{
37-
ArrayCapacityConstant folder;
38-
expr->accept_vis (folder);
39-
*folded_result = folder.result;
40-
return folder.ok;
41-
}
42-
43-
void visit (AST::LiteralExpr &expr) override
44-
{
45-
switch (expr.get_lit_type ())
46-
{
47-
case AST::Literal::LitType::INT: {
48-
ok = true;
49-
std::stringstream ss (expr.as_string ());
50-
ss >> result;
51-
}
52-
break;
53-
54-
default:
55-
return;
56-
}
57-
}
58-
59-
private:
60-
ArrayCapacityConstant () : ok (false), result (-1) {}
61-
62-
bool ok;
63-
size_t result;
64-
}; // namespace Resolver
65-
6630
class ASTLowerPathInExpression : public ASTLoweringBase
6731
{
6832
using Rust::HIR::ASTLoweringBase::visit;
@@ -332,18 +296,9 @@ class ASTLoweringExpr : public ASTLoweringBase
332296
HIR::Expr *num_copies
333297
= ASTLoweringExpr::translate (elems.get_num_copies ().get ());
334298

335-
size_t folded;
336-
if (!ArrayCapacityConstant::fold (elems.get_num_copies ().get (), &folded))
337-
{
338-
rust_fatal_error (elems.get_num_copies ()->get_locus_slow (),
339-
"failed to fold capacity constant");
340-
return;
341-
}
342-
343299
translated_array_elems
344300
= new HIR::ArrayElemsCopied (std::unique_ptr<HIR::Expr> (element),
345-
std::unique_ptr<HIR::Expr> (num_copies),
346-
folded);
301+
std::unique_ptr<HIR::Expr> (num_copies));
347302
}
348303

349304
void visit (AST::LiteralExpr &expr) override

gcc/rust/hir/tree/rust-hir-expr.h

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -825,8 +825,6 @@ class ArrayElems
825825

826826
virtual void accept_vis (HIRVisitor &vis) = 0;
827827

828-
virtual size_t get_num_elements () const = 0;
829-
830828
protected:
831829
// pure virtual clone implementation
832830
virtual ArrayElems *clone_array_elems_impl () const = 0;
@@ -870,7 +868,7 @@ class ArrayElemsValues : public ArrayElems
870868

871869
void accept_vis (HIRVisitor &vis) override;
872870

873-
size_t get_num_elements () const override { return values.size (); }
871+
size_t get_num_elements () const { return values.size (); }
874872

875873
void iterate (std::function<bool (Expr *)> cb)
876874
{
@@ -893,33 +891,26 @@ class ArrayElemsCopied : public ArrayElems
893891
{
894892
std::unique_ptr<Expr> elem_to_copy;
895893
std::unique_ptr<Expr> num_copies;
896-
size_t folded_copy_amount;
897-
898-
// TODO: should this store location data?
899894

900895
public:
901896
// Constructor requires pointers for polymorphism
902897
ArrayElemsCopied (std::unique_ptr<Expr> copied_elem,
903-
std::unique_ptr<Expr> copy_amount,
904-
size_t folded_copy_amount)
898+
std::unique_ptr<Expr> copy_amount)
905899
: elem_to_copy (std::move (copied_elem)),
906-
num_copies (std::move (copy_amount)),
907-
folded_copy_amount (folded_copy_amount)
900+
num_copies (std::move (copy_amount))
908901
{}
909902

910903
// Copy constructor required due to unique_ptr - uses custom clone
911904
ArrayElemsCopied (ArrayElemsCopied const &other)
912905
: elem_to_copy (other.elem_to_copy->clone_expr ()),
913-
num_copies (other.num_copies->clone_expr ()),
914-
folded_copy_amount (other.folded_copy_amount)
906+
num_copies (other.num_copies->clone_expr ())
915907
{}
916908

917909
// Overloaded assignment operator for deep copying
918910
ArrayElemsCopied &operator= (ArrayElemsCopied const &other)
919911
{
920912
elem_to_copy = other.elem_to_copy->clone_expr ();
921913
num_copies = other.num_copies->clone_expr ();
922-
folded_copy_amount = other.folded_copy_amount;
923914

924915
return *this;
925916
}
@@ -932,10 +923,10 @@ class ArrayElemsCopied : public ArrayElems
932923

933924
void accept_vis (HIRVisitor &vis) override;
934925

935-
size_t get_num_elements () const override { return folded_copy_amount; }
936-
937926
Expr *get_elem_to_copy () { return elem_to_copy.get (); }
938927

928+
Expr *get_num_copies_expr () { return num_copies.get (); }
929+
939930
protected:
940931
ArrayElemsCopied *clone_array_elems_impl () const override
941932
{

gcc/rust/resolve/rust-ast-resolve-type.h

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -217,10 +217,7 @@ class ResolveType : public ResolverBase
217217
}
218218
}
219219

220-
void visit (AST::ArrayType &type) override
221-
{
222-
type.get_elem_type ()->accept_vis (*this);
223-
}
220+
void visit (AST::ArrayType &type) override;
224221

225222
void visit (AST::ReferenceType &type) override
226223
{

gcc/rust/resolve/rust-ast-resolve.cc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -589,5 +589,14 @@ ResolvePath::resolve_path (AST::PathInExpression *expr)
589589
}
590590
}
591591

592+
// rust-ast-resolve-type.h
593+
594+
void
595+
ResolveType::visit (AST::ArrayType &type)
596+
{
597+
type.get_elem_type ()->accept_vis (*this);
598+
ResolveExpr::go (type.get_size_expr ().get (), type.get_node_id ());
599+
}
600+
592601
} // namespace Resolver
593602
} // namespace Rust

gcc/rust/rust-backend.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,11 @@ class Backend
9393
virtual void debug (Bvariable *) = 0;
9494
virtual void debug (Blabel *) = 0;
9595

96+
// const folder helpers
97+
virtual bool const_size_cast (Bexpression *, size_t *) = 0;
98+
virtual std::string const_size_val_to_string (Bexpression *) = 0;
99+
virtual bool const_values_equal (Bexpression *, Bexpression *) = 0;
100+
96101
// Types.
97102

98103
// Produce an error type. Actually the backend could probably just
@@ -283,6 +288,9 @@ class Backend
283288
// going without crashing.
284289
virtual Bexpression *error_expression () = 0;
285290

291+
// return whether this is error_mark_node
292+
virtual bool is_error_expression (Bexpression *) = 0;
293+
286294
// Create a nil pointer expression.
287295
virtual Bexpression *nil_pointer_expression () = 0;
288296

gcc/rust/rust-gcc.cc

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,6 @@ class Gcc_backend : public Backend
167167
void debug (Blabel *t) { debug_tree (t->get_tree ()); };
168168

169169
// Types.
170-
171170
Btype *error_type () { return this->make_type (error_mark_node); }
172171

173172
Btype *void_type () { return this->make_type (void_type_node); }
@@ -176,6 +175,46 @@ class Gcc_backend : public Backend
176175

177176
Btype *char_type () { return this->make_type (char_type_node); }
178177

178+
bool const_size_cast (Bexpression *expr, size_t *result)
179+
{
180+
rust_assert (TREE_CONSTANT (expr->get_tree ()));
181+
182+
unsigned char buf[sizeof (size_t) + 1];
183+
memset (buf, 0, sizeof (buf));
184+
185+
int ret = native_encode_expr (expr->get_tree (), buf, sizeof (buf), 0);
186+
if (ret <= 0)
187+
return false;
188+
189+
size_t *tmp = (size_t *) buf;
190+
*result = *tmp;
191+
return true;
192+
}
193+
194+
std::string const_size_val_to_string (Bexpression *expr)
195+
{
196+
rust_assert (TREE_CONSTANT (expr->get_tree ()));
197+
198+
unsigned char buf[sizeof (size_t) + 1];
199+
memset (buf, 0, sizeof (buf));
200+
201+
int ret = native_encode_expr (expr->get_tree (), buf, sizeof (buf), 0);
202+
rust_assert (ret > 0);
203+
204+
size_t *ptr = (size_t *) buf;
205+
return std::to_string (*ptr);
206+
}
207+
208+
bool const_values_equal (Bexpression *a, Bexpression *b)
209+
{
210+
return operand_equal_p (a->get_tree (), b->get_tree (),
211+
OEP_ONLY_CONST | OEP_PURE_SAME);
212+
// printf ("comparing!\n");
213+
// debug_tree (a->get_tree ());
214+
// debug_tree (b->get_tree ());
215+
// printf ("ok = %s\n", ok ? "true" : "false");
216+
}
217+
179218
Btype *wchar_type ()
180219
{
181220
// i think this is meant to be 32 bit from
@@ -250,6 +289,11 @@ class Gcc_backend : public Backend
250289
return this->make_expression (error_mark_node);
251290
}
252291

292+
bool is_error_expression (Bexpression *expr)
293+
{
294+
return expr->get_tree () == error_mark_node;
295+
}
296+
253297
Bexpression *nil_pointer_expression ()
254298
{
255299
return this->make_expression (null_pointer_node);

gcc/rust/rust-session-manager.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
#include "rust-hir-scan-deadcode.h"
5353
#include "rust-tycheck-dump.h"
5454
#include "rust-ast-resolve-unused.h"
55+
#include "rust-hir-const-fold.h"
5556
#include "rust-compile.h"
5657

5758
extern Linemap *
@@ -325,6 +326,9 @@ Session::init ()
325326

326327
// setup backend to GCC GIMPLE
327328
backend = rust_get_backend ();
329+
330+
// the constant folder uses gcc
331+
ConstFold::Context::init (backend);
328332
}
329333

330334
/* Initialise default options. Actually called before handle_option, unlike init

0 commit comments

Comments
 (0)