aboutsummaryrefslogtreecommitdiff
path: root/gcc/rust/backend
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/rust/backend')
-rw-r--r--gcc/rust/backend/rust-compile-base.cc24
-rw-r--r--gcc/rust/backend/rust-compile-base.h2
-rw-r--r--gcc/rust/backend/rust-compile-context.h24
-rw-r--r--gcc/rust/backend/rust-compile-expr.cc73
-rw-r--r--gcc/rust/backend/rust-compile-extern.h46
-rw-r--r--gcc/rust/backend/rust-compile-pattern.cc510
-rw-r--r--gcc/rust/backend/rust-compile-resolve-path.cc7
-rw-r--r--gcc/rust/backend/rust-compile-type.cc98
-rw-r--r--gcc/rust/backend/rust-compile-type.h5
-rw-r--r--gcc/rust/backend/rust-compile-var-decl.h70
-rw-r--r--gcc/rust/backend/rust-compile.cc14
-rw-r--r--gcc/rust/backend/rust-constexpr.cc698
12 files changed, 1204 insertions, 367 deletions
diff --git a/gcc/rust/backend/rust-compile-base.cc b/gcc/rust/backend/rust-compile-base.cc
index 73c34b2..d1db58e 100644
--- a/gcc/rust/backend/rust-compile-base.cc
+++ b/gcc/rust/backend/rust-compile-base.cc
@@ -32,6 +32,7 @@
#include "rust-type-util.h"
#include "rust-compile-implitem.h"
#include "rust-attribute-values.h"
+#include "rust-attributes.h"
#include "rust-immutable-name-resolution-context.h"
#include "fold-const.h"
@@ -251,25 +252,21 @@ void
HIRCompileBase::handle_link_section_attribute_on_fndecl (
tree fndecl, const AST::Attribute &attr)
{
- if (!attr.has_attr_input ())
+ auto msg_str = Analysis::Attributes::extract_string_literal (attr);
+
+ if (!msg_str.has_value ())
{
rust_error_at (attr.get_locus (),
- "%<link_section%> expects exactly one argment");
+ "malformed %<link_section%> attribute input");
return;
}
- rust_assert (attr.get_attr_input ().get_attr_input_type ()
- == AST::AttrInput::AttrInputType::LITERAL);
-
- auto &literal = static_cast<AST::AttrInputLiteral &> (attr.get_attr_input ());
- const auto &msg_str = literal.get_literal ().as_string ();
-
if (decl_section_name (fndecl))
{
rust_warning_at (attr.get_locus (), 0, "section name redefined");
}
- set_decl_section_name (fndecl, msg_str.c_str ());
+ set_decl_section_name (fndecl, msg_str->c_str ());
}
void
@@ -416,13 +413,10 @@ HIRCompileBase::handle_must_use_attribute_on_fndecl (tree fndecl,
if (attr.has_attr_input ())
{
- rust_assert (attr.get_attr_input ().get_attr_input_type ()
- == AST::AttrInput::AttrInputType::LITERAL);
+ auto msg_str = Analysis::Attributes::extract_string_literal (attr);
+ rust_assert (msg_str.has_value ());
- auto &literal
- = static_cast<AST::AttrInputLiteral &> (attr.get_attr_input ());
- const auto &msg_str = literal.get_literal ().as_string ();
- tree message = build_string (msg_str.size (), msg_str.c_str ());
+ tree message = build_string (msg_str->size (), msg_str->c_str ());
value = tree_cons (nodiscard, message, NULL_TREE);
}
diff --git a/gcc/rust/backend/rust-compile-base.h b/gcc/rust/backend/rust-compile-base.h
index e9b8596..3bf26af 100644
--- a/gcc/rust/backend/rust-compile-base.h
+++ b/gcc/rust/backend/rust-compile-base.h
@@ -56,7 +56,7 @@ protected:
TyTy::BaseType *expected, location_t lvalue_locus,
location_t rvalue_locus);
- tree coerce_to_dyn_object (tree compiled_ref, const TyTy::BaseType *actual,
+ tree coerce_to_dyn_object (tree compiled_ref, TyTy::BaseType *actual,
const TyTy::DynamicObjectType *ty,
location_t locus);
diff --git a/gcc/rust/backend/rust-compile-context.h b/gcc/rust/backend/rust-compile-context.h
index d4a642b..e98bbc2 100644
--- a/gcc/rust/backend/rust-compile-context.h
+++ b/gcc/rust/backend/rust-compile-context.h
@@ -34,6 +34,10 @@ namespace Compile {
struct fncontext
{
+ fncontext (tree fndecl, ::Bvariable *ret_addr, TyTy::BaseType *retty)
+ : fndecl (fndecl), ret_addr (ret_addr), retty (retty)
+ {}
+
tree fndecl;
::Bvariable *ret_addr;
TyTy::BaseType *retty;
@@ -154,7 +158,7 @@ public:
if (it == mono_fns.end ())
mono_fns[dId] = {};
- mono_fns[dId].push_back ({ref, fn});
+ mono_fns[dId].emplace_back (ref, fn);
}
void insert_closure_decl (const TyTy::ClosureType *ref, tree fn)
@@ -164,7 +168,7 @@ public:
if (it == mono_closure_fns.end ())
mono_closure_fns[dId] = {};
- mono_closure_fns[dId].push_back ({ref, fn});
+ mono_closure_fns[dId].emplace_back (ref, fn);
}
tree lookup_closure_decl (const TyTy::ClosureType *ref)
@@ -279,7 +283,7 @@ public:
void push_fn (tree fn, ::Bvariable *ret_addr, TyTy::BaseType *retty)
{
- fn_stack.push_back (fncontext{fn, ret_addr, retty});
+ fn_stack.emplace_back (fn, ret_addr, retty);
}
void pop_fn () { fn_stack.pop_back (); }
@@ -318,7 +322,13 @@ public:
void push_loop_context (Bvariable *var) { loop_value_stack.push_back (var); }
- Bvariable *peek_loop_context () { return loop_value_stack.back (); }
+ bool have_loop_context () const { return !loop_value_stack.empty (); }
+
+ Bvariable *peek_loop_context ()
+ {
+ rust_assert (!loop_value_stack.empty ());
+ return loop_value_stack.back ();
+ }
Bvariable *pop_loop_context ()
{
@@ -332,7 +342,11 @@ public:
loop_begin_labels.push_back (label);
}
- tree peek_loop_begin_label () { return loop_begin_labels.back (); }
+ tree peek_loop_begin_label ()
+ {
+ rust_assert (!loop_begin_labels.empty ());
+ return loop_begin_labels.back ();
+ }
tree pop_loop_begin_label ()
{
diff --git a/gcc/rust/backend/rust-compile-expr.cc b/gcc/rust/backend/rust-compile-expr.cc
index 6433923..0a627f3 100644
--- a/gcc/rust/backend/rust-compile-expr.cc
+++ b/gcc/rust/backend/rust-compile-expr.cc
@@ -828,6 +828,10 @@ CompileExpr::visit (HIR::BreakExpr &expr)
{
tree compiled_expr = CompileExpr::Compile (expr.get_expr (), ctx);
+ translated = error_mark_node;
+ if (!ctx->have_loop_context ())
+ return;
+
Bvariable *loop_result_holder = ctx->peek_loop_context ();
tree result_reference
= Backend::var_expression (loop_result_holder,
@@ -891,6 +895,10 @@ CompileExpr::visit (HIR::BreakExpr &expr)
void
CompileExpr::visit (HIR::ContinueExpr &expr)
{
+ translated = error_mark_node;
+ if (!ctx->have_loop_context ())
+ return;
+
tree label = ctx->peek_loop_begin_label ();
if (expr.has_label ())
{
@@ -1647,37 +1655,39 @@ CompileExpr::compile_integer_literal (const HIR::LiteralExpr &expr,
const TyTy::BaseType *tyty)
{
rust_assert (expr.get_lit_type () == HIR::Literal::INT);
- const auto literal_value = expr.get_literal ();
-
+ const auto &literal_value = expr.get_literal ();
tree type = TyTyResolveCompile::compile (ctx, tyty);
+ std::string s = literal_value.as_string ();
+ s.erase (std::remove (s.begin (), s.end (), '_'), s.end ());
+
+ int base = 0;
mpz_t ival;
- if (mpz_init_set_str (ival, literal_value.as_string ().c_str (), 10) != 0)
+ if (mpz_init_set_str (ival, s.c_str (), base) != 0)
{
- rust_error_at (expr.get_locus (), "bad number in literal");
+ rust_error_at (expr.get_locus (), "failed to load number literal");
return error_mark_node;
}
+ if (expr.is_negative ())
+ mpz_neg (ival, ival);
- mpz_t type_min;
- mpz_t type_max;
+ mpz_t type_min, type_max;
mpz_init (type_min);
mpz_init (type_max);
get_type_static_bounds (type, type_min, type_max);
- if (expr.is_negative ())
- {
- mpz_neg (ival, ival);
- }
if (mpz_cmp (ival, type_min) < 0 || mpz_cmp (ival, type_max) > 0)
{
rust_error_at (expr.get_locus (),
"integer overflows the respective type %qs",
tyty->get_name ().c_str ());
+ mpz_clear (type_min);
+ mpz_clear (type_max);
+ mpz_clear (ival);
return error_mark_node;
}
tree result = wide_int_to_tree (type, wi::from_mpz (type, ival, true));
-
mpz_clear (type_min);
mpz_clear (type_max);
mpz_clear (ival);
@@ -2000,13 +2010,25 @@ CompileExpr::array_copied_expr (location_t expr_locus,
return error_mark_node;
}
- ctx->push_const_context ();
- tree capacity_expr = CompileExpr::Compile (elems.get_num_copies_expr (), ctx);
- ctx->pop_const_context ();
+ auto capacity_ty = array_tyty.get_capacity ();
+
+ // Check if capacity is a const type
+ if (capacity_ty->get_kind () != TyTy::TypeKind::CONST)
+ {
+ rust_error_at (array_tyty.get_locus (),
+ "array capacity is not a const type");
+ return error_mark_node;
+ }
+
+ auto *capacity_const = capacity_ty->as_const_type ();
- if (!TREE_CONSTANT (capacity_expr))
+ rust_assert (capacity_const->const_kind ()
+ == TyTy::BaseConstType::ConstKind::Value);
+ auto &capacity_value = *static_cast<TyTy::ConstValueType *> (capacity_const);
+ auto cap_tree = capacity_value.get_value ();
+ if (error_operand_p (cap_tree) || !TREE_CONSTANT (cap_tree))
{
- rust_error_at (expr_locus, "non const num copies %qT", array_type);
+ rust_error_at (expr_locus, "non const num copies %qT", cap_tree);
return error_mark_node;
}
@@ -2059,9 +2081,9 @@ CompileExpr::array_copied_expr (location_t expr_locus,
ctx->push_block (init_block);
tree tmp;
- tree stmts = Backend::array_initializer (fndecl, init_block, array_type,
- capacity_expr, translated_expr,
- &tmp, expr_locus);
+ tree stmts
+ = Backend::array_initializer (fndecl, init_block, array_type, cap_tree,
+ translated_expr, &tmp, expr_locus);
ctx->add_statement (stmts);
tree block = ctx->pop_block ();
@@ -2209,11 +2231,10 @@ HIRCompileBase::resolve_unsized_dyn_adjustment (
tree rvalue = expression;
location_t rvalue_locus = locus;
- const TyTy::BaseType *actual = adjustment.get_actual ();
- const TyTy::BaseType *expected = adjustment.get_expected ();
+ auto actual = adjustment.get_actual ();
+ auto expected = adjustment.get_expected ();
- const TyTy::DynamicObjectType *dyn
- = static_cast<const TyTy::DynamicObjectType *> (expected);
+ const auto dyn = static_cast<const TyTy::DynamicObjectType *> (expected);
rust_debug ("resolve_unsized_dyn_adjustment actual={%s} dyn={%s}",
actual->debug_str ().c_str (), dyn->debug_str ().c_str ());
@@ -2617,15 +2638,15 @@ CompileExpr::generate_closure_fntype (HIR::ClosureExpr &expr,
TyTy::TypeBoundPredicateItem item = TyTy::TypeBoundPredicateItem::error ();
if (predicate.get_name ().compare ("FnOnce") == 0)
{
- item = predicate.lookup_associated_item ("call_once");
+ item = predicate.lookup_associated_item ("call_once").value ();
}
else if (predicate.get_name ().compare ("FnMut") == 0)
{
- item = predicate.lookup_associated_item ("call_mut");
+ item = predicate.lookup_associated_item ("call_mut").value ();
}
else if (predicate.get_name ().compare ("Fn") == 0)
{
- item = predicate.lookup_associated_item ("call");
+ item = predicate.lookup_associated_item ("call").value ();
}
else
{
diff --git a/gcc/rust/backend/rust-compile-extern.h b/gcc/rust/backend/rust-compile-extern.h
index d6aa589..a78f9ee 100644
--- a/gcc/rust/backend/rust-compile-extern.h
+++ b/gcc/rust/backend/rust-compile-extern.h
@@ -24,6 +24,8 @@
#include "rust-compile-type.h"
#include "rust-diagnostics.h"
#include "rust-hir-full-decls.h"
+#include "rust-attributes.h"
+#include "rust-attribute-values.h"
namespace Rust {
namespace Compile {
@@ -57,8 +59,7 @@ public:
rust_assert (ok);
std::string name = item.get_item_name ().as_string ();
- // FIXME this is assuming C ABI
- std::string asm_name = name;
+ GGC::Ident asm_name = get_link_name (item);
tree type = TyTyResolveCompile::compile (ctx, resolved_type);
bool is_external = true;
@@ -124,16 +125,7 @@ public:
tree compiled_fn_type = TyTyResolveCompile::compile (ctx, fntype);
std::string ir_symbol_name = function.get_item_name ().as_string ();
- std::string asm_name = function.get_item_name ().as_string ();
- if (fntype->get_abi () == ABI::RUST)
- {
- // then we need to get the canonical path of it and mangle it
- auto canonical_path = ctx->get_mappings ().lookup_canonical_path (
- function.get_mappings ().get_nodeid ());
-
- ir_symbol_name = canonical_path->get () + fntype->subst_as_string ();
- asm_name = ctx->mangle_item (fntype, *canonical_path);
- }
+ GGC::Ident asm_name = get_link_name (function);
const unsigned int flags = Backend::function_is_declaration;
tree fndecl = Backend::function (compiled_fn_type, ir_symbol_name, asm_name,
@@ -158,6 +150,36 @@ private:
ref_locus (ref_locus)
{}
+ template <typename T> static GGC::Ident get_link_name (T &obj)
+ {
+ AST::Attribute *use_attr = nullptr;
+
+ for (auto &attr : obj.get_outer_attrs ())
+ {
+ if (attr.get_path ().as_string () == Values::Attributes::LINK_NAME)
+ {
+ // later attributes override earlier ones
+ // TODO: add warning -- should duplicate
+ // attributes be folded elsewhere?
+ use_attr = &attr;
+ }
+ }
+
+ if (use_attr)
+ {
+ auto link_name
+ = Analysis::Attributes::extract_string_literal (*use_attr);
+
+ if (!link_name.has_value ())
+ rust_error_at (use_attr->get_locus (),
+ "malformed %<link_name%> attribute input");
+ else
+ return *link_name;
+ }
+
+ return obj.get_item_name ();
+ }
+
TyTy::BaseType *concrete;
tree reference;
location_t ref_locus;
diff --git a/gcc/rust/backend/rust-compile-pattern.cc b/gcc/rust/backend/rust-compile-pattern.cc
index fe65921..82333dc 100644
--- a/gcc/rust/backend/rust-compile-pattern.cc
+++ b/gcc/rust/backend/rust-compile-pattern.cc
@@ -27,6 +27,7 @@
#include "rust-hir-pattern.h"
#include "rust-system.h"
#include "rust-tyty.h"
+#include "tree.h"
namespace Rust {
namespace Compile {
@@ -158,13 +159,15 @@ CompilePatternCheckExpr::visit (HIR::RangePattern &pattern)
pattern.get_mappings (),
pattern.get_locus (), ctx);
+ ComparisonOperator upper_cmp = pattern.is_inclusive_range ()
+ ? ComparisonOperator::LESS_OR_EQUAL
+ : ComparisonOperator::LESS_THAN;
tree check_lower
= Backend::comparison_expression (ComparisonOperator::GREATER_OR_EQUAL,
match_scrutinee_expr, lower,
pattern.get_locus ());
tree check_upper
- = Backend::comparison_expression (ComparisonOperator::LESS_OR_EQUAL,
- match_scrutinee_expr, upper,
+ = Backend::comparison_expression (upper_cmp, match_scrutinee_expr, upper,
pattern.get_locus ());
check_expr = Backend::arithmetic_or_logical_expression (
ArithmeticOrLogicalOperator::BITWISE_AND, check_lower, check_upper,
@@ -354,17 +357,51 @@ CompilePatternCheckExpr::visit (HIR::TupleStructPattern &pattern)
HIR::TupleStructItems &items = pattern.get_items ();
switch (items.get_item_type ())
{
- case HIR::TupleStructItems::RANGED:
+ case HIR::TupleStructItems::HAS_REST:
{
- // TODO
- rust_unreachable ();
+ HIR::TupleStructItemsHasRest &items_has_rest
+ = static_cast<HIR::TupleStructItemsHasRest &> (items);
+ size_t num_patterns = items_has_rest.get_lower_patterns ().size ()
+ + items_has_rest.get_upper_patterns ().size ();
+
+ // enums cases shouldn't reach here
+ rust_assert (num_patterns <= variant->num_fields ()
+ && (!adt->is_enum ()));
+
+ size_t tuple_field_index = 0;
+ for (auto &pattern : items_has_rest.get_lower_patterns ())
+ {
+ tree field_expr
+ = Backend::struct_field_expression (match_scrutinee_expr,
+ tuple_field_index++,
+ pattern->get_locus ());
+ tree check_expr_sub
+ = CompilePatternCheckExpr::Compile (*pattern, field_expr, ctx);
+ check_expr = Backend::arithmetic_or_logical_expression (
+ ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
+ check_expr_sub, pattern->get_locus ());
+ }
+ tuple_field_index = variant->num_fields ()
+ - items_has_rest.get_upper_patterns ().size ();
+ for (auto &pattern : items_has_rest.get_upper_patterns ())
+ {
+ tree field_expr
+ = Backend::struct_field_expression (match_scrutinee_expr,
+ tuple_field_index++,
+ pattern->get_locus ());
+ tree check_expr_sub
+ = CompilePatternCheckExpr::Compile (*pattern, field_expr, ctx);
+ check_expr = Backend::arithmetic_or_logical_expression (
+ ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
+ check_expr_sub, pattern->get_locus ());
+ }
}
break;
- case HIR::TupleStructItems::MULTIPLE:
+ case HIR::TupleStructItems::NO_REST:
{
- HIR::TupleStructItemsNoRange &items_no_range
- = static_cast<HIR::TupleStructItemsNoRange &> (items);
+ HIR::TupleStructItemsNoRest &items_no_range
+ = static_cast<HIR::TupleStructItemsNoRest &> (items);
rust_assert (items_no_range.get_patterns ().size ()
== variant->num_fields ());
@@ -428,10 +465,10 @@ CompilePatternCheckExpr::visit (HIR::TuplePattern &pattern)
switch (pattern.get_items ().get_item_type ())
{
- case HIR::TuplePatternItems::RANGED:
+ case HIR::TuplePatternItems::HAS_REST:
{
auto &items
- = static_cast<HIR::TuplePatternItemsRanged &> (pattern.get_items ());
+ = static_cast<HIR::TuplePatternItemsHasRest &> (pattern.get_items ());
size_t tuple_field_index = 0;
// lookup the type to find out number of fields
@@ -477,10 +514,10 @@ CompilePatternCheckExpr::visit (HIR::TuplePattern &pattern)
}
break;
- case HIR::TuplePatternItems::MULTIPLE:
+ case HIR::TuplePatternItems::NO_REST:
{
- auto &items = static_cast<HIR::TuplePatternItemsMultiple &> (
- pattern.get_items ());
+ auto &items
+ = static_cast<HIR::TuplePatternItemsNoRest &> (pattern.get_items ());
size_t tuple_field_index = 0;
for (auto &pat : items.get_patterns ())
@@ -532,25 +569,14 @@ CompilePatternCheckExpr::visit (HIR::SlicePattern &pattern)
|| lookup->get_kind () == TyTy::TypeKind::SLICE
|| lookup->get_kind () == TyTy::REF);
- size_t array_element_index = 0;
+ // function ptr that points to either array_index_expression or
+ // slice_index_expression depending on the scrutinee's type
+ tree (*scrutinee_index_expr_func) (tree, tree, location_t) = nullptr;
+
switch (lookup->get_kind ())
{
case TyTy::TypeKind::ARRAY:
- for (auto &pattern_member : pattern.get_items ())
- {
- tree array_index_tree
- = Backend::size_constant_expression (array_element_index++);
- tree element_expr
- = Backend::array_index_expression (match_scrutinee_expr,
- array_index_tree,
- pattern.get_locus ());
- tree check_expr_sub
- = CompilePatternCheckExpr::Compile (*pattern_member, element_expr,
- ctx);
- check_expr = Backend::arithmetic_or_logical_expression (
- ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
- check_expr_sub, pattern.get_locus ());
- }
+ scrutinee_index_expr_func = Backend::array_index_expression;
break;
case TyTy::TypeKind::SLICE:
rust_sorry_at (
@@ -560,25 +586,81 @@ CompilePatternCheckExpr::visit (HIR::SlicePattern &pattern)
case TyTy::TypeKind::REF:
{
rust_assert (RS_DST_FLAG_P (TREE_TYPE (match_scrutinee_expr)));
+ scrutinee_index_expr_func = Backend::slice_index_expression;
tree size_field
= Backend::struct_field_expression (match_scrutinee_expr, 1,
pattern.get_locus ());
- // First compare the size
- check_expr = Backend::comparison_expression (
- ComparisonOperator::EQUAL, size_field,
- build_int_cst (size_type_node, pattern.get_items ().size ()),
- pattern.get_locus ());
+ // for slices, generate a dynamic size comparison expression tree
+ // because size checking is done at runtime.
+ switch (pattern.get_items ().get_item_type ())
+ {
+ case HIR::SlicePatternItems::ItemType::NO_REST:
+ {
+ auto &items = static_cast<HIR::SlicePatternItemsNoRest &> (
+ pattern.get_items ());
+ check_expr = Backend::comparison_expression (
+ ComparisonOperator::EQUAL, size_field,
+ build_int_cst (size_type_node, items.get_patterns ().size ()),
+ pattern.get_locus ());
+ }
+ break;
+ case HIR::SlicePatternItems::ItemType::HAS_REST:
+ {
+ auto &items = static_cast<HIR::SlicePatternItemsHasRest &> (
+ pattern.get_items ());
+ auto pattern_min_cap = items.get_lower_patterns ().size ()
+ + items.get_upper_patterns ().size ();
+ check_expr = Backend::comparison_expression (
+ ComparisonOperator::GREATER_OR_EQUAL, size_field,
+ build_int_cst (size_type_node, pattern_min_cap),
+ pattern.get_locus ());
+ }
+ break;
+ }
+ }
+ break;
+ default:
+ rust_unreachable ();
+ }
+
+ rust_assert (scrutinee_index_expr_func != nullptr);
- // Then compare each element in the slice pattern
- for (auto &pattern_member : pattern.get_items ())
+ // Generate tree to compare every element within array/slice
+ size_t element_index = 0;
+ switch (pattern.get_items ().get_item_type ())
+ {
+ case HIR::SlicePatternItems::ItemType::NO_REST:
+ {
+ auto &items
+ = static_cast<HIR::SlicePatternItemsNoRest &> (pattern.get_items ());
+ for (auto &pattern_member : items.get_patterns ())
{
- tree slice_index_tree
- = Backend::size_constant_expression (array_element_index++);
+ tree index_tree
+ = Backend::size_constant_expression (element_index++);
tree element_expr
- = Backend::slice_index_expression (match_scrutinee_expr,
- slice_index_tree,
- pattern.get_locus ());
+ = scrutinee_index_expr_func (match_scrutinee_expr, index_tree,
+ pattern.get_locus ());
+ tree check_expr_sub
+ = CompilePatternCheckExpr::Compile (*pattern_member, element_expr,
+ ctx);
+ check_expr = Backend::arithmetic_or_logical_expression (
+ ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
+ check_expr_sub, pattern.get_locus ());
+ }
+ break;
+ }
+ case HIR::SlicePatternItems::ItemType::HAS_REST:
+ {
+ auto &items
+ = static_cast<HIR::SlicePatternItemsHasRest &> (pattern.get_items ());
+ for (auto &pattern_member : items.get_lower_patterns ())
+ {
+ tree index_tree
+ = Backend::size_constant_expression (element_index++);
+ tree element_expr
+ = scrutinee_index_expr_func (match_scrutinee_expr, index_tree,
+ pattern.get_locus ());
tree check_expr_sub
= CompilePatternCheckExpr::Compile (*pattern_member, element_expr,
ctx);
@@ -586,10 +668,82 @@ CompilePatternCheckExpr::visit (HIR::SlicePattern &pattern)
ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
check_expr_sub, pattern.get_locus ());
}
+
+ // handle codegen for upper patterns differently for both types
+ switch (lookup->get_kind ())
+ {
+ case TyTy::TypeKind::ARRAY:
+ {
+ // for array type scrutinee, we can simply get the capacity as a
+ // const and calculate how many elements to skip
+ auto array_ty = static_cast<TyTy::ArrayType *> (lookup);
+ auto capacity_ty = array_ty->get_capacity ();
+
+ rust_assert (capacity_ty->get_kind () == TyTy::TypeKind::CONST);
+ auto *capacity_const = capacity_ty->as_const_type ();
+ rust_assert (capacity_const->const_kind ()
+ == TyTy::BaseConstType::ConstKind::Value);
+ auto &capacity_value
+ = *static_cast<TyTy::ConstValueType *> (capacity_const);
+ auto cap_tree = capacity_value.get_value ();
+
+ rust_assert (!error_operand_p (cap_tree));
+
+ size_t cap_wi = (size_t) wi::to_wide (cap_tree).to_uhwi ();
+ element_index = cap_wi - items.get_upper_patterns ().size ();
+ for (auto &pattern_member : items.get_upper_patterns ())
+ {
+ tree index_tree
+ = Backend::size_constant_expression (element_index++);
+ tree element_expr
+ = scrutinee_index_expr_func (match_scrutinee_expr,
+ index_tree,
+ pattern.get_locus ());
+ tree check_expr_sub
+ = CompilePatternCheckExpr::Compile (*pattern_member,
+ element_expr, ctx);
+ check_expr = Backend::arithmetic_or_logical_expression (
+ ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
+ check_expr_sub, pattern.get_locus ());
+ }
+ }
+ break;
+ case TyTy::TypeKind::REF:
+ {
+ // for slice type scrutinee, size is dyanamic, so number of
+ // elements to skip is calculated during runtime
+ tree slice_size
+ = Backend::struct_field_expression (match_scrutinee_expr, 1,
+ pattern.get_locus ());
+ tree upper_patterns_size = Backend::size_constant_expression (
+ items.get_upper_patterns ().size ());
+ tree index_tree = Backend::arithmetic_or_logical_expression (
+ ArithmeticOrLogicalOperator::SUBTRACT, slice_size,
+ upper_patterns_size, pattern.get_locus ());
+ for (auto &pattern_member : items.get_upper_patterns ())
+ {
+ tree element_expr
+ = scrutinee_index_expr_func (match_scrutinee_expr,
+ index_tree,
+ pattern.get_locus ());
+ tree check_expr_sub
+ = CompilePatternCheckExpr::Compile (*pattern_member,
+ element_expr, ctx);
+ check_expr = Backend::arithmetic_or_logical_expression (
+ ArithmeticOrLogicalOperator::BITWISE_AND, check_expr,
+ check_expr_sub, pattern.get_locus ());
+ index_tree = Backend::arithmetic_or_logical_expression (
+ ArithmeticOrLogicalOperator::ADD, index_tree,
+ Backend::size_constant_expression (1),
+ pattern.get_locus ());
+ }
+ }
+ break;
+ default:
+ rust_unreachable ();
+ }
}
break;
- default:
- rust_unreachable ();
}
}
@@ -628,25 +782,54 @@ CompilePatternBindings::visit (HIR::TupleStructPattern &pattern)
HIR::TupleStructItems &items = pattern.get_items ();
switch (items.get_item_type ())
{
- case HIR::TupleStructItems::RANGED:
+ case HIR::TupleStructItems::HAS_REST:
{
- // TODO
- rust_unreachable ();
+ HIR::TupleStructItemsHasRest &items_has_rest
+ = static_cast<HIR::TupleStructItemsHasRest &> (items);
+ size_t num_patterns = items_has_rest.get_lower_patterns ().size ()
+ + items_has_rest.get_upper_patterns ().size ();
+
+ // enums cases shouldn't reach here
+ rust_assert (num_patterns <= variant->num_fields ()
+ && (!adt->is_enum ()));
+
+ size_t tuple_field_index = 0;
+ for (auto &pattern : items_has_rest.get_lower_patterns ())
+ {
+ tree binding
+ = Backend::struct_field_expression (match_scrutinee_expr,
+ tuple_field_index++,
+ pattern->get_locus ());
+
+ CompilePatternBindings::Compile (*pattern, binding, ctx);
+ }
+
+ tuple_field_index = variant->num_fields ()
+ - items_has_rest.get_upper_patterns ().size ();
+
+ for (auto &pattern : items_has_rest.get_upper_patterns ())
+ {
+ tree binding
+ = Backend::struct_field_expression (match_scrutinee_expr,
+ tuple_field_index++,
+ pattern->get_locus ());
+
+ CompilePatternBindings::Compile (*pattern, binding, ctx);
+ }
}
break;
- case HIR::TupleStructItems::MULTIPLE:
+ case HIR::TupleStructItems::NO_REST:
{
- HIR::TupleStructItemsNoRange &items_no_range
- = static_cast<HIR::TupleStructItemsNoRange &> (items);
-
- rust_assert (items_no_range.get_patterns ().size ()
+ HIR::TupleStructItemsNoRest &items_no_rest
+ = static_cast<HIR::TupleStructItemsNoRest &> (items);
+ rust_assert (items_no_rest.get_patterns ().size ()
== variant->num_fields ());
if (adt->is_enum ())
{
size_t tuple_field_index = 0;
- for (auto &pattern : items_no_range.get_patterns ())
+ for (auto &pattern : items_no_rest.get_patterns ())
{
tree payload_accessor_union
= Backend::struct_field_expression (match_scrutinee_expr, 1,
@@ -668,12 +851,10 @@ CompilePatternBindings::visit (HIR::TupleStructPattern &pattern)
else
{
size_t tuple_field_index = 0;
- for (auto &pattern : items_no_range.get_patterns ())
+ for (auto &pattern : items_no_rest.get_patterns ())
{
- tree variant_accessor = match_scrutinee_expr;
-
tree binding
- = Backend::struct_field_expression (variant_accessor,
+ = Backend::struct_field_expression (match_scrutinee_expr,
tuple_field_index++,
pattern->get_locus ());
@@ -777,8 +958,9 @@ CompilePatternBindings::visit (HIR::StructPattern &pattern)
rust_assert (ok);
}
- rust_assert (variant->get_variant_type ()
- == TyTy::VariantDef::VariantType::STRUCT);
+ rust_assert (
+ variant->get_variant_type () == TyTy::VariantDef::VariantType::STRUCT
+ || variant->get_variant_type () == TyTy::VariantDef::VariantType::TUPLE);
auto &struct_pattern_elems = pattern.get_struct_pattern_elems ();
for (auto &field : struct_pattern_elems.get_struct_pattern_fields ())
@@ -843,11 +1025,11 @@ CompilePatternBindings::visit (HIR::TuplePattern &pattern)
switch (pattern.get_items ().get_item_type ())
{
- case HIR::TuplePatternItems::ItemType::RANGED:
+ case HIR::TuplePatternItems::ItemType::HAS_REST:
{
size_t tuple_idx = 0;
auto &items
- = static_cast<HIR::TuplePatternItemsRanged &> (pattern.get_items ());
+ = static_cast<HIR::TuplePatternItemsHasRest &> (pattern.get_items ());
auto &items_lower = items.get_lower_patterns ();
auto &items_upper = items.get_upper_patterns ();
@@ -887,11 +1069,11 @@ CompilePatternBindings::visit (HIR::TuplePattern &pattern)
return;
}
- case HIR::TuplePatternItems::ItemType::MULTIPLE:
+ case HIR::TuplePatternItems::ItemType::NO_REST:
{
size_t tuple_idx = 0;
- auto &items = static_cast<HIR::TuplePatternItemsMultiple &> (
- pattern.get_items ());
+ auto &items
+ = static_cast<HIR::TuplePatternItemsNoRest &> (pattern.get_items ());
for (auto &sub : items.get_patterns ())
{
@@ -930,43 +1112,132 @@ CompilePatternBindings::visit (HIR::SlicePattern &pattern)
|| lookup->get_kind () == TyTy::TypeKind::SLICE
|| lookup->get_kind () == TyTy::REF);
- size_t array_element_index = 0;
+ // function ptr that points to either array_index_expression or
+ // slice_index_expression depending on the scrutinee's type
+ tree (*scrutinee_index_expr_func) (tree, tree, location_t) = nullptr;
+
switch (lookup->get_kind ())
{
case TyTy::TypeKind::ARRAY:
- for (auto &pattern_member : pattern.get_items ())
- {
- tree array_index_tree
- = Backend::size_constant_expression (array_element_index++);
- tree element_expr
- = Backend::array_index_expression (match_scrutinee_expr,
- array_index_tree,
- pattern.get_locus ());
- CompilePatternBindings::Compile (*pattern_member, element_expr, ctx);
- }
+ scrutinee_index_expr_func = Backend::array_index_expression;
break;
case TyTy::TypeKind::SLICE:
- rust_sorry_at (
- pattern.get_locus (),
- "SlicePattern matching against non-ref slices are not yet supported");
+ rust_sorry_at (pattern.get_locus (),
+ "SlicePattern matching against non-ref slices are "
+ "not yet supported");
break;
case TyTy::TypeKind::REF:
+ scrutinee_index_expr_func = Backend::slice_index_expression;
+ break;
+ default:
+ rust_unreachable ();
+ }
+
+ rust_assert (scrutinee_index_expr_func != nullptr);
+
+ size_t element_index = 0;
+
+ switch (pattern.get_items ().get_item_type ())
+ {
+ case HIR::SlicePatternItems::ItemType::NO_REST:
{
- for (auto &pattern_member : pattern.get_items ())
+ auto &items
+ = static_cast<HIR::SlicePatternItemsNoRest &> (pattern.get_items ());
+ for (auto &pattern_member : items.get_patterns ())
{
- tree slice_index_tree
- = Backend::size_constant_expression (array_element_index++);
+ tree index_tree
+ = Backend::size_constant_expression (element_index++);
tree element_expr
- = Backend::slice_index_expression (match_scrutinee_expr,
- slice_index_tree,
- pattern.get_locus ());
+ = scrutinee_index_expr_func (match_scrutinee_expr, index_tree,
+ pattern.get_locus ());
CompilePatternBindings::Compile (*pattern_member, element_expr,
ctx);
}
- break;
}
- default:
- rust_unreachable ();
+ break;
+ case HIR::SlicePatternItems::ItemType::HAS_REST:
+ {
+ auto &items
+ = static_cast<HIR::SlicePatternItemsHasRest &> (pattern.get_items ());
+ for (auto &pattern_member : items.get_lower_patterns ())
+ {
+ tree index_tree
+ = Backend::size_constant_expression (element_index++);
+ tree element_expr
+ = scrutinee_index_expr_func (match_scrutinee_expr, index_tree,
+ pattern.get_locus ());
+ CompilePatternBindings::Compile (*pattern_member, element_expr,
+ ctx);
+ }
+
+ // handle codegen for upper patterns differently for both types
+ switch (lookup->get_kind ())
+ {
+ case TyTy::TypeKind::ARRAY:
+ {
+ auto array_ty = static_cast<TyTy::ArrayType *> (lookup);
+ auto capacity_ty = array_ty->get_capacity ();
+
+ rust_assert (capacity_ty->get_kind () == TyTy::TypeKind::CONST);
+ auto *capacity_const = capacity_ty->as_const_type ();
+ rust_assert (capacity_const->const_kind ()
+ == TyTy::BaseConstType::ConstKind::Value);
+ auto &capacity_value
+ = *static_cast<TyTy::ConstValueType *> (capacity_const);
+ auto cap_tree = capacity_value.get_value ();
+
+ rust_assert (!error_operand_p (cap_tree));
+
+ size_t cap_wi = (size_t) wi::to_wide (cap_tree).to_uhwi ();
+ element_index = cap_wi - items.get_upper_patterns ().size ();
+ for (auto &pattern_member : items.get_upper_patterns ())
+ {
+ tree index_tree
+ = Backend::size_constant_expression (element_index++);
+ tree element_expr
+ = scrutinee_index_expr_func (match_scrutinee_expr,
+ index_tree,
+ pattern.get_locus ());
+ CompilePatternBindings::Compile (*pattern_member,
+ element_expr, ctx);
+ }
+ }
+ break;
+ case TyTy::TypeKind::SLICE:
+ rust_sorry_at (pattern.get_locus (),
+ "SlicePattern matching against non-ref slices are "
+ "not yet supported");
+ break;
+ case TyTy::TypeKind::REF:
+ {
+ tree slice_size
+ = Backend::struct_field_expression (match_scrutinee_expr, 1,
+ pattern.get_locus ());
+ tree upper_patterns_size = Backend::size_constant_expression (
+ items.get_upper_patterns ().size ());
+ tree index_tree = Backend::arithmetic_or_logical_expression (
+ ArithmeticOrLogicalOperator::SUBTRACT, slice_size,
+ upper_patterns_size, pattern.get_locus ());
+ for (auto &pattern_member : items.get_upper_patterns ())
+ {
+ tree element_expr
+ = scrutinee_index_expr_func (match_scrutinee_expr,
+ index_tree,
+ pattern.get_locus ());
+ CompilePatternBindings::Compile (*pattern_member,
+ element_expr, ctx);
+ index_tree = Backend::arithmetic_or_logical_expression (
+ ArithmeticOrLogicalOperator::ADD, index_tree,
+ Backend::size_constant_expression (1),
+ pattern.get_locus ());
+ }
+ }
+ break;
+ default:
+ rust_unreachable ();
+ }
+ }
+ break;
}
}
@@ -979,6 +1250,11 @@ CompilePatternLet::visit (HIR::IdentifierPattern &pattern)
rust_assert (
ctx->lookup_var_decl (pattern.get_mappings ().get_hirid (), &var));
+ if (pattern.get_is_ref ())
+ {
+ init_expr = address_expression (init_expr, EXPR_LOCATION (init_expr));
+ }
+
auto fnctx = ctx->peek_fn ();
if (ty->is_unit ())
{
@@ -990,6 +1266,11 @@ CompilePatternLet::visit (HIR::IdentifierPattern &pattern)
}
else
{
+ if (pattern.has_subpattern ())
+ {
+ CompilePatternLet::Compile (&pattern.get_subpattern (), init_expr, ty,
+ rval_locus, ctx);
+ }
auto s = Backend::init_statement (fnctx.fndecl, var, init_expr);
ctx->add_statement (s);
}
@@ -1013,22 +1294,65 @@ CompilePatternLet::visit (HIR::TuplePattern &pattern)
{
rust_assert (pattern.has_tuple_pattern_items ());
- tree tuple_type = TyTyResolveCompile::compile (ctx, ty);
+ bool has_by_ref = false;
+ auto check_refs
+ = [] (const std::vector<std::unique_ptr<HIR::Pattern>> &patterns) {
+ for (const auto &sub : patterns)
+ {
+ switch (sub->get_pattern_type ())
+ {
+ case HIR::Pattern::PatternType::IDENTIFIER:
+ {
+ auto id = static_cast<HIR::IdentifierPattern *> (sub.get ());
+ if (id->get_is_ref ())
+ return true;
+ break;
+ }
+ case HIR::Pattern::PatternType::REFERENCE:
+ return true;
+ default:
+ break;
+ }
+ }
+ return false;
+ };
+ switch (pattern.get_items ().get_item_type ())
+ {
+ case HIR::TuplePatternItems::ItemType::NO_REST:
+ {
+ auto &items
+ = static_cast<HIR::TuplePatternItemsNoRest &> (pattern.get_items ());
+ has_by_ref = check_refs (items.get_patterns ());
+ break;
+ }
+ case HIR::TuplePatternItems::ItemType::HAS_REST:
+ {
+ auto &items
+ = static_cast<HIR::TuplePatternItemsHasRest &> (pattern.get_items ());
+ has_by_ref = check_refs (items.get_lower_patterns ())
+ || check_refs (items.get_upper_patterns ());
+ break;
+ }
+ default:
+ break;
+ }
+
+ tree rhs_tuple_type = TYPE_MAIN_VARIANT (TREE_TYPE (init_expr));
tree init_stmt;
Bvariable *tmp_var
= Backend::temporary_variable (ctx->peek_fn ().fndecl, NULL_TREE,
- tuple_type, init_expr, false,
+ rhs_tuple_type, init_expr, has_by_ref,
pattern.get_locus (), &init_stmt);
tree access_expr = Backend::var_expression (tmp_var, pattern.get_locus ());
ctx->add_statement (init_stmt);
switch (pattern.get_items ().get_item_type ())
{
- case HIR::TuplePatternItems::ItemType::RANGED:
+ case HIR::TuplePatternItems::ItemType::HAS_REST:
{
size_t tuple_idx = 0;
auto &items
- = static_cast<HIR::TuplePatternItemsRanged &> (pattern.get_items ());
+ = static_cast<HIR::TuplePatternItemsHasRest &> (pattern.get_items ());
auto &items_lower = items.get_lower_patterns ();
auto &items_upper = items.get_upper_patterns ();
@@ -1069,11 +1393,11 @@ CompilePatternLet::visit (HIR::TuplePattern &pattern)
return;
}
- case HIR::TuplePatternItems::ItemType::MULTIPLE:
+ case HIR::TuplePatternItems::ItemType::NO_REST:
{
size_t tuple_idx = 0;
- auto &items = static_cast<HIR::TuplePatternItemsMultiple &> (
- pattern.get_items ());
+ auto &items
+ = static_cast<HIR::TuplePatternItemsNoRest &> (pattern.get_items ());
for (auto &sub : items.get_patterns ())
{
diff --git a/gcc/rust/backend/rust-compile-resolve-path.cc b/gcc/rust/backend/rust-compile-resolve-path.cc
index f3b9dc2..c33d0b0 100644
--- a/gcc/rust/backend/rust-compile-resolve-path.cc
+++ b/gcc/rust/backend/rust-compile-resolve-path.cc
@@ -97,8 +97,11 @@ ResolvePathRef::attempt_constructor_expression_lookup (
// this can only be for discriminant variants the others are built up
// using call-expr or struct-init
- rust_assert (variant->get_variant_type ()
- == TyTy::VariantDef::VariantType::NUM);
+ if (variant->get_variant_type () != TyTy::VariantDef::VariantType::NUM)
+ {
+ rust_error_at (expr_locus, "variant expected constructor call");
+ return error_mark_node;
+ }
// we need the actual gcc type
tree compiled_adt_type = TyTyResolveCompile::compile (ctx, adt);
diff --git a/gcc/rust/backend/rust-compile-type.cc b/gcc/rust/backend/rust-compile-type.cc
index 0622954..5b00afa 100644
--- a/gcc/rust/backend/rust-compile-type.cc
+++ b/gcc/rust/backend/rust-compile-type.cc
@@ -136,13 +136,31 @@ TyTyResolveCompile::visit (const TyTy::InferType &type)
}
void
-TyTyResolveCompile::visit (const TyTy::ParamType &)
+TyTyResolveCompile::visit (const TyTy::ParamType &type)
{
translated = error_mark_node;
}
void
-TyTyResolveCompile::visit (const TyTy::ConstType &)
+TyTyResolveCompile::visit (const TyTy::ConstParamType &type)
+{
+ translated = error_mark_node;
+}
+
+void
+TyTyResolveCompile::visit (const TyTy::ConstValueType &type)
+{
+ translated = error_mark_node;
+}
+
+void
+TyTyResolveCompile::visit (const TyTy::ConstInferType &type)
+{
+ translated = error_mark_node;
+}
+
+void
+TyTyResolveCompile::visit (const TyTy::ConstErrorType &type)
{
translated = error_mark_node;
}
@@ -186,8 +204,8 @@ TyTyResolveCompile::visit (const TyTy::ClosureType &type)
// this should be based on the closure move-ability
tree decl_type = TyTyResolveCompile::compile (ctx, lookup);
tree capture_type = build_reference_type (decl_type);
- fields.push_back (Backend::typed_identifier (mappings_name, capture_type,
- type.get_ident ().locus));
+ fields.emplace_back (mappings_name, capture_type,
+ type.get_ident ().locus);
}
tree type_record = Backend::struct_type (fields);
@@ -217,8 +235,7 @@ TyTyResolveCompile::visit (const TyTy::FnType &type)
auto ret = TyTyResolveCompile::compile (ctx, hir_type, trait_object_mode);
location_t return_type_locus
= ctx->get_mappings ().lookup_location (hir_type->get_ref ());
- results.push_back (
- Backend::typed_identifier ("_", ret, return_type_locus));
+ results.emplace_back ("_", ret, return_type_locus);
}
for (auto &param_pair : type.get_params ())
@@ -227,11 +244,10 @@ TyTyResolveCompile::visit (const TyTy::FnType &type)
auto compiled_param_type
= TyTyResolveCompile::compile (ctx, param_tyty, trait_object_mode);
- auto compiled_param = Backend::typed_identifier (
- param_pair.get_pattern ().as_string (), compiled_param_type,
- ctx->get_mappings ().lookup_location (param_tyty->get_ref ()));
-
- parameters.push_back (compiled_param);
+ parameters.emplace_back (param_pair.get_pattern ().as_string (),
+ compiled_param_type,
+ ctx->get_mappings ().lookup_location (
+ param_tyty->get_ref ()));
}
if (!type.is_variadic ())
@@ -277,10 +293,9 @@ TyTyResolveCompile::visit (const TyTy::ADTType &type)
tree compiled_field_ty
= TyTyResolveCompile::compile (ctx, field->get_field_type ());
- Backend::typed_identifier f (field->get_name (), compiled_field_ty,
- ctx->get_mappings ().lookup_location (
- type.get_ty_ref ()));
- fields.push_back (std::move (f));
+ fields.emplace_back (field->get_name (), compiled_field_ty,
+ ctx->get_mappings ().lookup_location (
+ type.get_ty_ref ()));
}
type_record = type.is_union () ? Backend::union_type (fields, false)
@@ -357,10 +372,9 @@ TyTyResolveCompile::visit (const TyTy::ADTType &type)
== TyTy::VariantDef::VariantType::TUPLE)
field_name = "__" + field->get_name ();
- Backend::typed_identifier f (
- field_name, compiled_field_ty,
- ctx->get_mappings ().lookup_location (type.get_ty_ref ()));
- fields.push_back (std::move (f));
+ fields.emplace_back (field_name, compiled_field_ty,
+ ctx->get_mappings ().lookup_location (
+ type.get_ty_ref ()));
}
tree variant_record = Backend::struct_type (fields);
@@ -382,10 +396,9 @@ TyTyResolveCompile::visit (const TyTy::ADTType &type)
TyTy::VariantDef *variant = type.get_variants ().at (i++);
std::string implicit_variant_name = variant->get_identifier ();
- Backend::typed_identifier f (implicit_variant_name, variant_record,
- ctx->get_mappings ().lookup_location (
- type.get_ty_ref ()));
- enum_fields.push_back (std::move (f));
+ enum_fields.emplace_back (implicit_variant_name, variant_record,
+ ctx->get_mappings ().lookup_location (
+ type.get_ty_ref ()));
}
//
@@ -460,10 +473,9 @@ TyTyResolveCompile::visit (const TyTy::TupleType &type)
// this, rather than simply emitting the integer, is that this
// approach makes it simpler to use a C-only debugger, or
// GDB's C mode, when debugging Rust.
- Backend::typed_identifier f ("__" + std::to_string (i), compiled_field_ty,
- ctx->get_mappings ().lookup_location (
- type.get_ty_ref ()));
- fields.push_back (std::move (f));
+ fields.emplace_back ("__" + std::to_string (i), compiled_field_ty,
+ ctx->get_mappings ().lookup_location (
+ type.get_ty_ref ()));
}
tree struct_type_record = Backend::struct_type (fields);
@@ -476,8 +488,22 @@ TyTyResolveCompile::visit (const TyTy::ArrayType &type)
{
tree element_type
= TyTyResolveCompile::compile (ctx, type.get_element_type ());
- TyTy::ConstType *const_capacity = type.get_capacity ();
- tree folded_capacity_expr = const_capacity->get_value ();
+ auto const_capacity = type.get_capacity ();
+
+ // Check if capacity is a const type
+ if (const_capacity->get_kind () != TyTy::TypeKind::CONST)
+ {
+ rust_error_at (type.get_locus (), "array capacity is not a const type");
+ translated = error_mark_node;
+ return;
+ }
+
+ auto *capacity_const = const_capacity->as_const_type ();
+
+ rust_assert (capacity_const->const_kind ()
+ == TyTy::BaseConstType::ConstKind::Value);
+ auto &capacity_value = *static_cast<TyTy::ConstValueType *> (capacity_const);
+ auto folded_capacity_expr = capacity_value.get_value ();
// build_index_type takes the maximum index, which is one less than
// the length.
@@ -772,17 +798,15 @@ TyTyResolveCompile::create_dyn_obj_record (const TyTy::DynamicObjectType &type)
tree uint = Backend::integer_type (true, Backend::get_pointer_size ());
tree uintptr_ty = build_pointer_type (uint);
- Backend::typed_identifier f ("pointer", uintptr_ty,
- ctx->get_mappings ().lookup_location (
- type.get_ty_ref ()));
- fields.push_back (std::move (f));
+ fields.emplace_back ("pointer", uintptr_ty,
+ ctx->get_mappings ().lookup_location (
+ type.get_ty_ref ()));
tree vtable_size = build_int_cst (size_type_node, items.size ());
tree vtable_type = Backend::array_type (uintptr_ty, vtable_size);
- Backend::typed_identifier vtf ("vtable", vtable_type,
- ctx->get_mappings ().lookup_location (
- type.get_ty_ref ()));
- fields.push_back (std::move (vtf));
+ fields.emplace_back ("vtable", vtable_type,
+ ctx->get_mappings ().lookup_location (
+ type.get_ty_ref ()));
tree record = Backend::struct_type (fields);
RS_DST_FLAG (record) = 1;
diff --git a/gcc/rust/backend/rust-compile-type.h b/gcc/rust/backend/rust-compile-type.h
index 0675343..d6c3259 100644
--- a/gcc/rust/backend/rust-compile-type.h
+++ b/gcc/rust/backend/rust-compile-type.h
@@ -50,7 +50,10 @@ public:
void visit (const TyTy::ReferenceType &) override;
void visit (const TyTy::PointerType &) override;
void visit (const TyTy::ParamType &) override;
- void visit (const TyTy::ConstType &) override;
+ void visit (const TyTy::ConstParamType &) override;
+ void visit (const TyTy::ConstValueType &) override;
+ void visit (const TyTy::ConstInferType &) override;
+ void visit (const TyTy::ConstErrorType &) override;
void visit (const TyTy::StrType &) override;
void visit (const TyTy::NeverType &) override;
void visit (const TyTy::PlaceholderType &) override;
diff --git a/gcc/rust/backend/rust-compile-var-decl.h b/gcc/rust/backend/rust-compile-var-decl.h
index 5c6d145..1f306ad 100644
--- a/gcc/rust/backend/rust-compile-var-decl.h
+++ b/gcc/rust/backend/rust-compile-var-decl.h
@@ -64,31 +64,79 @@ public:
ctx->insert_var_decl (stmt_id, var);
vars.push_back (var);
+
+ if (pattern.has_subpattern ())
+ {
+ auto subpattern_vars
+ = CompileVarDecl::compile (fndecl, translated_type,
+ &pattern.get_subpattern (), ctx);
+ vars.insert (vars.end (), subpattern_vars.begin (),
+ subpattern_vars.end ());
+ }
}
void visit (HIR::TuplePattern &pattern) override
{
+ rust_assert (TREE_CODE (translated_type) == RECORD_TYPE);
switch (pattern.get_items ().get_item_type ())
{
- case HIR::TuplePatternItems::ItemType::MULTIPLE:
+ case HIR::TuplePatternItems::ItemType::NO_REST:
{
- rust_assert (TREE_CODE (translated_type) == RECORD_TYPE);
- auto &items = static_cast<HIR::TuplePatternItemsMultiple &> (
+ auto &items_no_rest = static_cast<HIR::TuplePatternItemsNoRest &> (
pattern.get_items ());
- size_t offs = 0;
- for (auto &sub : items.get_patterns ())
+ tree field = TYPE_FIELDS (translated_type);
+ for (auto &sub : items_no_rest.get_patterns ())
{
- tree sub_ty = error_mark_node;
- tree field = TYPE_FIELDS (translated_type);
- for (size_t i = 0; i < offs; i++)
+ gcc_assert (field != NULL_TREE);
+ tree sub_ty = TREE_TYPE (field);
+ CompileVarDecl::compile (fndecl, sub_ty, sub.get (), ctx);
+ field = DECL_CHAIN (field);
+ }
+ }
+ break;
+
+ case HIR::TuplePatternItems::ItemType::HAS_REST:
+ {
+ auto &items_has_rest = static_cast<HIR::TuplePatternItemsHasRest &> (
+ pattern.get_items ());
+
+ // count total fields in translated_type
+ size_t total_fields = 0;
+ for (tree t = TYPE_FIELDS (translated_type); t; t = DECL_CHAIN (t))
+ {
+ total_fields++;
+ }
+
+ // process lower patterns
+ tree field = TYPE_FIELDS (translated_type);
+ for (auto &sub : items_has_rest.get_lower_patterns ())
+ {
+ gcc_assert (field != NULL_TREE);
+ tree sub_ty = TREE_TYPE (field);
+ CompileVarDecl::compile (fndecl, sub_ty, sub.get (), ctx);
+ field = DECL_CHAIN (field);
+ }
+
+ // process upper patterns
+ if (!items_has_rest.get_upper_patterns ().empty ())
+ {
+ size_t upper_start
+ = total_fields - items_has_rest.get_upper_patterns ().size ();
+ field = TYPE_FIELDS (translated_type);
+ for (size_t i = 0; i < upper_start; i++)
{
field = DECL_CHAIN (field);
gcc_assert (field != NULL_TREE);
}
- sub_ty = TREE_TYPE (field);
- CompileVarDecl::compile (fndecl, sub_ty, sub.get (), ctx);
- offs++;
+
+ for (auto &sub : items_has_rest.get_upper_patterns ())
+ {
+ gcc_assert (field != NULL_TREE);
+ tree sub_ty = TREE_TYPE (field);
+ CompileVarDecl::compile (fndecl, sub_ty, sub.get (), ctx);
+ field = DECL_CHAIN (field);
+ }
}
}
break;
diff --git a/gcc/rust/backend/rust-compile.cc b/gcc/rust/backend/rust-compile.cc
index dbd8515..40f16e4 100644
--- a/gcc/rust/backend/rust-compile.cc
+++ b/gcc/rust/backend/rust-compile.cc
@@ -183,8 +183,7 @@ HIRCompileBase::coercion_site1 (tree rvalue, TyTy::BaseType *rval,
}
tree
-HIRCompileBase::coerce_to_dyn_object (tree compiled_ref,
- const TyTy::BaseType *actual,
+HIRCompileBase::coerce_to_dyn_object (tree compiled_ref, TyTy::BaseType *actual,
const TyTy::DynamicObjectType *ty,
location_t locus)
{
@@ -201,9 +200,7 @@ HIRCompileBase::coerce_to_dyn_object (tree compiled_ref,
// __trait_object_ptr
// [list of function ptrs]
- std::vector<std::pair<Resolver::TraitReference *, HIR::ImplBlock *>>
- probed_bounds_for_receiver = Resolver::TypeBoundsProbe::Probe (actual);
-
+ auto probed_bounds_for_receiver = Resolver::TypeBoundsProbe::Probe (actual);
tree address_of_compiled_ref = null_pointer_node;
if (!actual->is_unit ())
address_of_compiled_ref = address_expression (compiled_ref, locus);
@@ -241,12 +238,13 @@ HIRCompileBase::compute_address_for_trait_item (
&receiver_bounds,
const TyTy::BaseType *receiver, const TyTy::BaseType *root, location_t locus)
{
- TyTy::TypeBoundPredicateItem predicate_item
+ tl::optional<TyTy::TypeBoundPredicateItem> predicate_item
= predicate->lookup_associated_item (ref->get_identifier ());
- rust_assert (!predicate_item.is_error ());
+ rust_assert (predicate_item.has_value ());
// This is the expected end type
- TyTy::BaseType *trait_item_type = predicate_item.get_tyty_for_receiver (root);
+ TyTy::BaseType *trait_item_type
+ = predicate_item->get_tyty_for_receiver (root);
rust_assert (trait_item_type->get_kind () == TyTy::TypeKind::FNDEF);
TyTy::FnType *trait_item_fntype
= static_cast<TyTy::FnType *> (trait_item_type);
diff --git a/gcc/rust/backend/rust-constexpr.cc b/gcc/rust/backend/rust-constexpr.cc
index d524d09..d04f864 100644
--- a/gcc/rust/backend/rust-constexpr.cc
+++ b/gcc/rust/backend/rust-constexpr.cc
@@ -101,12 +101,54 @@ struct constexpr_global_ctx
auto_vec<tree, 16> heap_vars;
/* Cleanups that need to be evaluated at the end of CLEANUP_POINT_EXPR. */
vec<tree> *cleanups;
+ /* If non-null, only allow modification of existing values of the variables
+ in this set. Set by modifiable_tracker, below. */
+ hash_set<tree> *modifiable;
/* Number of heap VAR_DECL deallocations. */
unsigned heap_dealloc_count;
/* Constructor. */
constexpr_global_ctx ()
: constexpr_ops_count (0), cleanups (NULL), heap_dealloc_count (0)
{}
+
+ tree get_value (tree t)
+ {
+ if (tree *p = values.get (t))
+ if (*p != void_node)
+ return *p;
+ return NULL_TREE;
+ }
+ tree *get_value_ptr (tree t, bool initializing)
+ {
+ if (modifiable && !modifiable->contains (t))
+ return nullptr;
+ if (tree *p = values.get (t))
+ {
+ if (*p != void_node)
+ return p;
+ else if (initializing)
+ {
+ *p = NULL_TREE;
+ return p;
+ }
+ }
+ return nullptr;
+ }
+ void put_value (tree t, tree v)
+ {
+ bool already_in_map = values.put (t, v);
+ if (!already_in_map && modifiable)
+ modifiable->add (t);
+ }
+ void destroy_value (tree t)
+ {
+ if (TREE_CODE (t) == VAR_DECL || TREE_CODE (t) == PARM_DECL
+ || TREE_CODE (t) == RESULT_DECL)
+ values.put (t, void_node);
+ else
+ values.remove (t);
+ }
+ void clear_value (tree t) { values.remove (t); }
};
/* In constexpr.cc */
@@ -457,23 +499,24 @@ save_fundef_copy (tree fun, tree copy)
static tree constant_value_1 (tree decl, bool strict_p,
bool return_aggregate_cst_ok_p, bool unshare_p);
+static tree decl_really_constant_value (tree decl, bool unshare_p /*= true*/);
tree decl_constant_value (tree decl, bool unshare_p);
static void non_const_var_error (location_t loc, tree r);
static tree eval_constant_expression (const constexpr_ctx *ctx, tree, bool,
- bool *, bool *, tree * = NULL);
+ bool *, bool *, tree *jump_target);
static tree constexpr_fn_retval (const constexpr_ctx *ctx, tree r);
static tree eval_store_expression (const constexpr_ctx *ctx, tree r, bool,
- bool *, bool *);
+ bool *, bool *, tree *jump_target);
static tree eval_call_expression (const constexpr_ctx *ctx, tree r, bool,
- bool *, bool *);
+ bool *, bool *, tree *);
static tree eval_binary_expression (const constexpr_ctx *ctx, tree r, bool,
- bool *, bool *);
+ bool *, bool *, tree *jump_target);
static tree get_function_named_in_call (tree t);
@@ -488,7 +531,8 @@ static tree eval_conditional_expression (const constexpr_ctx *ctx, tree t,
bool *overflow_p, tree *jump_target);
static tree eval_bit_field_ref (const constexpr_ctx *ctx, tree t, bool lval,
- bool *non_constant_p, bool *overflow_p);
+ bool *non_constant_p, bool *overflow_p,
+ tree *jump_target);
static tree eval_loop_expr (const constexpr_ctx *ctx, tree t,
bool *non_constant_p, bool *overflow_p,
@@ -500,7 +544,15 @@ static tree eval_switch_expr (const constexpr_ctx *ctx, tree t,
static tree eval_unary_expression (const constexpr_ctx *ctx, tree t,
bool /*lval*/, bool *non_constant_p,
- bool *overflow_p);
+ bool *overflow_p, tree *jump_target);
+static bool eval_check_shift_p (location_t loc, const constexpr_ctx *ctx,
+ enum tree_code code, tree type, tree lhs,
+ tree rhs);
+static tree fold_pointer_plus_expression (const constexpr_ctx *ctx, tree t,
+ tree lhs, tree rhs,
+ bool *non_constant_p,
+ bool *overflow_p, tree *jump_target);
+static tree maybe_fold_addr_pointer_plus (tree t);
/* Variables and functions to manage constexpr call expansion context.
These do not need to be marked for PCH or GC. */
@@ -562,8 +614,9 @@ fold_expr (tree expr)
bool non_constant_p = false;
bool overflow_p = false;
+ tree jump_target = NULL_TREE;
tree folded = eval_constant_expression (&ctx, expr, false, &non_constant_p,
- &overflow_p);
+ &overflow_p, &jump_target);
rust_assert (folded != NULL_TREE);
// more logic here to possibly port
@@ -589,13 +642,13 @@ same_type_ignoring_tlq_and_bounds_p (tree type1, tree type2)
otherwise return NULL_TREE. */
static tree
-union_active_member (const constexpr_ctx *ctx, tree t)
+union_active_member (const constexpr_ctx *ctx, tree t, tree *jump_target)
{
constexpr_ctx new_ctx = *ctx;
new_ctx.quiet = true;
bool non_constant_p = false, overflow_p = false;
tree ctor = eval_constant_expression (&new_ctx, t, false, &non_constant_p,
- &overflow_p);
+ &overflow_p, jump_target);
if (TREE_CODE (ctor) == CONSTRUCTOR && CONSTRUCTOR_NELTS (ctor) == 1
&& CONSTRUCTOR_ELT (ctor, 0)->index
&& TREE_CODE (CONSTRUCTOR_ELT (ctor, 0)->index) == FIELD_DECL)
@@ -607,7 +660,8 @@ union_active_member (const constexpr_ctx *ctx, tree t)
static tree
fold_indirect_ref_1 (const constexpr_ctx *ctx, location_t loc, tree type,
- tree op, unsigned HOST_WIDE_INT off, bool *empty_base)
+ tree op, unsigned HOST_WIDE_INT off, bool *empty_base,
+ tree *jump_target)
{
tree optype = TREE_TYPE (op);
unsigned HOST_WIDE_INT const_nunits;
@@ -654,7 +708,8 @@ fold_indirect_ref_1 (const constexpr_ctx *ctx, location_t loc, tree type,
tree index = size_int (idx + tree_to_uhwi (min_val));
op = build4_loc (loc, ARRAY_REF, TREE_TYPE (optype), op, index,
NULL_TREE, NULL_TREE);
- return fold_indirect_ref_1 (ctx, loc, type, op, rem, empty_base);
+ return fold_indirect_ref_1 (ctx, loc, type, op, rem, empty_base,
+ jump_target);
}
}
/* ((foo *)&struct_with_foo_field)[x] => COMPONENT_REF */
@@ -663,7 +718,7 @@ fold_indirect_ref_1 (const constexpr_ctx *ctx, location_t loc, tree type,
{
if (TREE_CODE (optype) == UNION_TYPE)
/* For unions prefer the currently active member. */
- if (tree field = union_active_member (ctx, op))
+ if (tree field = union_active_member (ctx, op, jump_target))
{
unsigned HOST_WIDE_INT el_sz
= tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (field)));
@@ -672,7 +727,7 @@ fold_indirect_ref_1 (const constexpr_ctx *ctx, location_t loc, tree type,
tree cop = build3 (COMPONENT_REF, TREE_TYPE (field), op, field,
NULL_TREE);
if (tree ret = fold_indirect_ref_1 (ctx, loc, type, cop, off,
- empty_base))
+ empty_base, jump_target))
return ret;
}
}
@@ -691,8 +746,9 @@ fold_indirect_ref_1 (const constexpr_ctx *ctx, location_t loc, tree type,
{
tree cop = build3 (COMPONENT_REF, TREE_TYPE (field), op, field,
NULL_TREE);
- if (tree ret = fold_indirect_ref_1 (ctx, loc, type, cop,
- off - upos, empty_base))
+ if (tree ret
+ = fold_indirect_ref_1 (ctx, loc, type, cop, off - upos,
+ empty_base, jump_target))
return ret;
}
}
@@ -721,7 +777,7 @@ fold_indirect_ref_1 (const constexpr_ctx *ctx, location_t loc, tree type,
static tree
rs_fold_indirect_ref (const constexpr_ctx *ctx, location_t loc, tree type,
- tree op0, bool *empty_base)
+ tree op0, bool *empty_base, tree *jump_target)
{
tree sub = op0;
tree subtype;
@@ -780,7 +836,8 @@ rs_fold_indirect_ref (const constexpr_ctx *ctx, location_t loc, tree type,
tree off = integer_zero_node;
canonicalize_obj_off (op, off);
gcc_assert (integer_zerop (off));
- return fold_indirect_ref_1 (ctx, loc, type, op, 0, empty_base);
+ return fold_indirect_ref_1 (ctx, loc, type, op, 0, empty_base,
+ jump_target);
}
}
else if (TREE_CODE (sub) == POINTER_PLUS_EXPR
@@ -795,7 +852,7 @@ rs_fold_indirect_ref (const constexpr_ctx *ctx, location_t loc, tree type,
tree obj = TREE_OPERAND (op00, 0);
canonicalize_obj_off (obj, off);
return fold_indirect_ref_1 (ctx, loc, type, obj, tree_to_uhwi (off),
- empty_base);
+ empty_base, jump_target);
}
}
/* *(foo *)fooarrptr => (*fooarrptr)[0] */
@@ -804,8 +861,8 @@ rs_fold_indirect_ref (const constexpr_ctx *ctx, location_t loc, tree type,
{
tree type_domain;
tree min_val = size_zero_node;
- tree newsub
- = rs_fold_indirect_ref (ctx, loc, TREE_TYPE (subtype), sub, NULL);
+ tree newsub = rs_fold_indirect_ref (ctx, loc, TREE_TYPE (subtype), sub,
+ NULL, jump_target);
if (newsub)
sub = newsub;
else
@@ -824,7 +881,7 @@ rs_fold_indirect_ref (const constexpr_ctx *ctx, location_t loc, tree type,
static tree
rs_eval_indirect_ref (const constexpr_ctx *ctx, tree t, bool lval,
- bool *non_constant_p, bool *overflow_p)
+ bool *non_constant_p, bool *overflow_p, tree *jump_target)
{
tree orig_op0 = TREE_OPERAND (t, 0);
bool empty_base = false;
@@ -842,13 +899,13 @@ rs_eval_indirect_ref (const constexpr_ctx *ctx, tree t, bool lval,
/* First try to simplify it directly. */
tree r = rs_fold_indirect_ref (ctx, EXPR_LOCATION (t), TREE_TYPE (t),
- orig_op0, &empty_base);
+ orig_op0, &empty_base, jump_target);
if (!r)
{
/* If that didn't work, evaluate the operand first. */
- tree op0
- = eval_constant_expression (ctx, orig_op0,
- /*lval*/ false, non_constant_p, overflow_p);
+ tree op0 = eval_constant_expression (ctx, orig_op0,
+ /*lval*/ false, non_constant_p,
+ overflow_p, jump_target);
/* Don't VERIFY_CONSTANT here. */
if (*non_constant_p)
return t;
@@ -862,7 +919,7 @@ rs_eval_indirect_ref (const constexpr_ctx *ctx, tree t, bool lval,
}
r = rs_fold_indirect_ref (ctx, EXPR_LOCATION (t), TREE_TYPE (t), op0,
- &empty_base);
+ &empty_base, jump_target);
if (r == NULL_TREE)
{
/* We couldn't fold to a constant value. Make sure it's not
@@ -891,7 +948,8 @@ rs_eval_indirect_ref (const constexpr_ctx *ctx, tree t, bool lval,
}
}
- r = eval_constant_expression (ctx, r, lval, non_constant_p, overflow_p);
+ r = eval_constant_expression (ctx, r, lval, non_constant_p, overflow_p,
+ jump_target);
if (*non_constant_p)
return t;
@@ -917,17 +975,17 @@ rs_eval_indirect_ref (const constexpr_ctx *ctx, tree t, bool lval,
static tree
eval_logical_expression (const constexpr_ctx *ctx, tree t, tree bailout_value,
tree continue_value, bool lval, bool *non_constant_p,
- bool *overflow_p)
+ bool *overflow_p, tree *jump_target)
{
tree r;
tree lhs = eval_constant_expression (ctx, TREE_OPERAND (t, 0), lval,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p, jump_target);
VERIFY_CONSTANT (lhs);
if (tree_int_cst_equal (lhs, bailout_value))
return lhs;
gcc_assert (tree_int_cst_equal (lhs, continue_value));
r = eval_constant_expression (ctx, TREE_OPERAND (t, 1), lval, non_constant_p,
- overflow_p);
+ overflow_p, jump_target);
VERIFY_CONSTANT (r);
return r;
}
@@ -1243,19 +1301,20 @@ get_or_insert_ctor_field (tree ctor, tree index, int pos_hint = -1)
static tree
eval_vector_conditional_expression (const constexpr_ctx *ctx, tree t,
- bool *non_constant_p, bool *overflow_p)
+ bool *non_constant_p, bool *overflow_p,
+ tree *jump_target)
{
- tree arg1
- = eval_constant_expression (ctx, TREE_OPERAND (t, 0),
- /*lval*/ false, non_constant_p, overflow_p);
+ tree arg1 = eval_constant_expression (ctx, TREE_OPERAND (t, 0),
+ /*lval*/ false, non_constant_p,
+ overflow_p, jump_target);
VERIFY_CONSTANT (arg1);
- tree arg2
- = eval_constant_expression (ctx, TREE_OPERAND (t, 1),
- /*lval*/ false, non_constant_p, overflow_p);
+ tree arg2 = eval_constant_expression (ctx, TREE_OPERAND (t, 1),
+ /*lval*/ false, non_constant_p,
+ overflow_p, jump_target);
VERIFY_CONSTANT (arg2);
- tree arg3
- = eval_constant_expression (ctx, TREE_OPERAND (t, 2),
- /*lval*/ false, non_constant_p, overflow_p);
+ tree arg3 = eval_constant_expression (ctx, TREE_OPERAND (t, 2),
+ /*lval*/ false, non_constant_p,
+ overflow_p, jump_target);
VERIFY_CONSTANT (arg3);
location_t loc = EXPR_LOCATION (t);
tree type = TREE_TYPE (t);
@@ -1280,7 +1339,7 @@ eval_vector_conditional_expression (const constexpr_ctx *ctx, tree t,
static tree
eval_bare_aggregate (const constexpr_ctx *ctx, tree t, bool lval,
- bool *non_constant_p, bool *overflow_p)
+ bool *non_constant_p, bool *overflow_p, tree *jump_target)
{
vec<constructor_elt, va_gc> *v = CONSTRUCTOR_ELTS (t);
bool changed = false;
@@ -1331,8 +1390,9 @@ eval_bare_aggregate (const constexpr_ctx *ctx, tree t, bool lval,
the active union member now so that we can later detect and diagnose
if its initializer attempts to activate another member. */
get_or_insert_ctor_field (ctx->ctor, index);
- tree elt = eval_constant_expression (&new_ctx, value, lval,
- non_constant_p, overflow_p);
+ tree elt
+ = eval_constant_expression (&new_ctx, value, lval, non_constant_p,
+ overflow_p, jump_target);
/* Don't VERIFY_CONSTANT here. */
if (ctx->quiet && *non_constant_p)
break;
@@ -1401,7 +1461,8 @@ eval_bare_aggregate (const constexpr_ctx *ctx, tree t, bool lval,
static tree
cxx_eval_trinary_expression (const constexpr_ctx *ctx, tree t, bool lval,
- bool *non_constant_p, bool *overflow_p)
+ bool *non_constant_p, bool *overflow_p,
+ tree *jump_target)
{
int i;
tree args[3];
@@ -1409,8 +1470,9 @@ cxx_eval_trinary_expression (const constexpr_ctx *ctx, tree t, bool lval,
for (i = 0; i < 3; i++)
{
- args[i] = eval_constant_expression (ctx, TREE_OPERAND (t, i), lval,
- non_constant_p, overflow_p);
+ args[i]
+ = eval_constant_expression (ctx, TREE_OPERAND (t, i), lval,
+ non_constant_p, overflow_p, jump_target);
VERIFY_CONSTANT (args[i]);
}
@@ -1555,7 +1617,8 @@ free_constructor (tree t)
static tree eval_and_check_array_index (const constexpr_ctx *ctx, tree t,
bool allow_one_past,
- bool *non_constant_p, bool *overflow_p);
+ bool *non_constant_p, bool *overflow_p,
+ tree *jump_target);
// forked from gcc/cp/constexpr.cc cxx_eval_array_reference
@@ -1564,11 +1627,11 @@ static tree eval_and_check_array_index (const constexpr_ctx *ctx, tree t,
static tree
eval_array_reference (const constexpr_ctx *ctx, tree t, bool lval,
- bool *non_constant_p, bool *overflow_p)
+ bool *non_constant_p, bool *overflow_p, tree *jump_target)
{
tree oldary = TREE_OPERAND (t, 0);
- tree ary
- = eval_constant_expression (ctx, oldary, lval, non_constant_p, overflow_p);
+ tree ary = eval_constant_expression (ctx, oldary, lval, non_constant_p,
+ overflow_p, jump_target);
if (*non_constant_p)
return t;
if (!lval && TREE_CODE (ary) == VIEW_CONVERT_EXPR
@@ -1577,8 +1640,8 @@ eval_array_reference (const constexpr_ctx *ctx, tree t, bool lval,
ary = TREE_OPERAND (ary, 0);
tree oldidx = TREE_OPERAND (t, 1);
- tree index
- = eval_and_check_array_index (ctx, t, lval, non_constant_p, overflow_p);
+ tree index = eval_and_check_array_index (ctx, t, lval, non_constant_p,
+ overflow_p, jump_target);
if (*non_constant_p)
return t;
@@ -1680,7 +1743,8 @@ eval_array_reference (const constexpr_ctx *ctx, tree t, bool lval,
new_ctx.ctor = build_constructor (elem_type, NULL);
ctx = &new_ctx;
}
- t = eval_constant_expression (ctx, val, lval, non_constant_p, overflow_p);
+ t = eval_constant_expression (ctx, val, lval, non_constant_p, overflow_p,
+ jump_target);
if (!SCALAR_TYPE_P (elem_type) && t != ctx->ctor)
free_constructor (ctx->ctor);
return t;
@@ -1693,7 +1757,8 @@ eval_array_reference (const constexpr_ctx *ctx, tree t, bool lval,
static tree
eval_component_reference (const constexpr_ctx *ctx, tree t, bool lval,
- bool *non_constant_p, bool *overflow_p)
+ bool *non_constant_p, bool *overflow_p,
+ tree *jump_target)
{
unsigned HOST_WIDE_INT i;
tree field;
@@ -1701,7 +1766,7 @@ eval_component_reference (const constexpr_ctx *ctx, tree t, bool lval,
tree part = TREE_OPERAND (t, 1);
tree orig_whole = TREE_OPERAND (t, 0);
tree whole = eval_constant_expression (ctx, orig_whole, lval, non_constant_p,
- overflow_p);
+ overflow_p, jump_target);
if (INDIRECT_REF_P (whole) && integer_zerop (TREE_OPERAND (whole, 0)))
{
if (!ctx->quiet)
@@ -1790,8 +1855,8 @@ eval_component_reference (const constexpr_ctx *ctx, tree t, bool lval,
// back to handle this to assign suitable value to value before sending it in
// eval_constant_expression below
// value = build_value_init (TREE_TYPE (t), tf_warning_or_error);
- return eval_constant_expression (ctx, value, lval, non_constant_p,
- overflow_p);
+ return eval_constant_expression (ctx, value, lval, non_constant_p, overflow_p,
+ jump_target);
}
/* Subroutine of cxx_eval_statement_list. Determine whether the statement
@@ -1850,7 +1915,7 @@ label_matches (const constexpr_ctx *ctx, tree *jump_target, tree stmt)
static tree
eval_constant_expression (const constexpr_ctx *ctx, tree t, bool lval,
bool *non_constant_p, bool *overflow_p,
- tree *jump_target /* = NULL */)
+ tree *jump_target)
{
if (jump_target && *jump_target)
{
@@ -1921,34 +1986,44 @@ eval_constant_expression (const constexpr_ctx *ctx, tree t, bool lval,
{
r = DECL_VALUE_EXPR (t);
return eval_constant_expression (ctx, r, lval, non_constant_p,
- overflow_p);
+ overflow_p, jump_target);
}
/* fall through */
case CONST_DECL:
- {
- /* We used to not check lval for CONST_DECL, but darwin.cc uses
- CONST_DECL for aggregate constants. */
- if (lval)
- return t;
- else if (t == ctx->object)
- return ctx->ctor;
- if (VAR_P (t))
- if (tree *p = ctx->global->values.get (t))
- if (*p != NULL_TREE)
- {
- r = *p;
- break;
- }
+ /* We used to not check lval for CONST_DECL, but darwin.cc uses
+ CONST_DECL for aggregate constants. */
+ if (lval)
+ return t;
+ else if (t == ctx->object)
+ return ctx->ctor;
+ if (VAR_P (t))
+ {
+ if (tree v = ctx->global->get_value (t))
+ {
+ r = v;
+ break;
+ }
+ }
+ if (COMPLETE_TYPE_P (TREE_TYPE (t))
+ && is_really_empty_class (TREE_TYPE (t), /*ignore_vptr*/ false))
+ {
+ /* If the class is empty, we aren't actually loading anything. */
+ r = build_constructor (TREE_TYPE (t), NULL);
+ TREE_CONSTANT (r) = true;
+ }
+ else if (ctx->strict)
+ r = decl_really_constant_value (t, /*unshare_p=*/false);
+ else
r = decl_constant_value (t, /*unshare_p=*/false);
- if (TREE_CODE (r) == TARGET_EXPR
- && TREE_CODE (TARGET_EXPR_INITIAL (r)) == CONSTRUCTOR)
- r = TARGET_EXPR_INITIAL (r);
- if (DECL_P (r))
- {
+ if (TREE_CODE (r) == TARGET_EXPR
+ && TREE_CODE (TARGET_EXPR_INITIAL (r)) == CONSTRUCTOR)
+ r = TARGET_EXPR_INITIAL (r);
+ if (DECL_P (r) && !(VAR_P (t) && TYPE_REF_P (TREE_TYPE (t))))
+ {
+ if (!ctx->quiet)
non_const_var_error (loc, r);
- return r;
- }
- }
+ *non_constant_p = true;
+ }
break;
case PARM_DECL:
@@ -2014,7 +2089,8 @@ eval_constant_expression (const constexpr_ctx *ctx, tree t, bool lval,
case LTGT_EXPR:
case RANGE_EXPR:
case COMPLEX_EXPR:
- r = eval_binary_expression (ctx, t, lval, non_constant_p, overflow_p);
+ r = eval_binary_expression (ctx, t, lval, non_constant_p, overflow_p,
+ jump_target);
break;
/* fold can introduce non-IF versions of these; still treat them as
@@ -2023,14 +2099,14 @@ eval_constant_expression (const constexpr_ctx *ctx, tree t, bool lval,
case TRUTH_ANDIF_EXPR:
r = eval_logical_expression (ctx, t, boolean_false_node,
boolean_true_node, lval, non_constant_p,
- overflow_p);
+ overflow_p, jump_target);
break;
case TRUTH_OR_EXPR:
case TRUTH_ORIF_EXPR:
r = eval_logical_expression (ctx, t, boolean_true_node,
boolean_false_node, lval, non_constant_p,
- overflow_p);
+ overflow_p, jump_target);
break;
case TARGET_EXPR:
@@ -2079,7 +2155,7 @@ eval_constant_expression (const constexpr_ctx *ctx, tree t, bool lval,
/* Pass false for 'lval' because this indicates
initialization of a temporary. */
r = eval_constant_expression (ctx, TREE_OPERAND (t, 1), false,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p, jump_target);
if (*non_constant_p)
break;
/* Adjust the type of the result to the type of the temporary. */
@@ -2096,13 +2172,14 @@ eval_constant_expression (const constexpr_ctx *ctx, tree t, bool lval,
break;
case CALL_EXPR:
- r = eval_call_expression (ctx, t, lval, non_constant_p, overflow_p);
+ r = eval_call_expression (ctx, t, lval, non_constant_p, overflow_p,
+ jump_target);
break;
case RETURN_EXPR:
if (TREE_OPERAND (t, 0) != NULL_TREE)
r = eval_constant_expression (ctx, TREE_OPERAND (t, 0), lval,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p, jump_target);
/* FALLTHRU */
case BREAK_STMT:
case CONTINUE_STMT:
@@ -2135,7 +2212,7 @@ eval_constant_expression (const constexpr_ctx *ctx, tree t, bool lval,
if (tree init = DECL_INITIAL (r))
{
init = eval_constant_expression (ctx, init, false, non_constant_p,
- overflow_p);
+ overflow_p, jump_target);
/* Don't share a CONSTRUCTOR that might be changed. */
init = unshare_constructor (init);
/* Remember that a constant object's constructor has already
@@ -2156,12 +2233,13 @@ eval_constant_expression (const constexpr_ctx *ctx, tree t, bool lval,
constant without its operand being, and vice versa. */
case MEM_REF:
case INDIRECT_REF:
- r = rs_eval_indirect_ref (ctx, t, lval, non_constant_p, overflow_p);
+ r = rs_eval_indirect_ref (ctx, t, lval, non_constant_p, overflow_p,
+ jump_target);
break;
case VEC_PERM_EXPR:
- r = cxx_eval_trinary_expression (ctx, t, lval, non_constant_p,
- overflow_p);
+ r = cxx_eval_trinary_expression (ctx, t, lval, non_constant_p, overflow_p,
+ jump_target);
break;
case PAREN_EXPR:
@@ -2169,11 +2247,12 @@ eval_constant_expression (const constexpr_ctx *ctx, tree t, bool lval,
/* A PAREN_EXPR resulting from __builtin_assoc_barrier has no effect in
constant expressions since it's unaffected by -fassociative-math. */
r = eval_constant_expression (ctx, TREE_OPERAND (t, 0), lval,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p, jump_target);
break;
case MODIFY_EXPR:
- r = eval_store_expression (ctx, t, false, non_constant_p, overflow_p);
+ r = eval_store_expression (ctx, t, false, non_constant_p, overflow_p,
+ jump_target);
break;
case STATEMENT_LIST:
@@ -2189,13 +2268,14 @@ eval_constant_expression (const constexpr_ctx *ctx, tree t, bool lval,
case OBJ_TYPE_REF:
/* Virtual function lookup. We don't need to do anything fancy. */
return eval_constant_expression (ctx, OBJ_TYPE_REF_EXPR (t), lval,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p, jump_target);
case EXIT_EXPR:
{
tree cond = TREE_OPERAND (t, 0);
- cond = eval_constant_expression (ctx, cond, /*lval*/ false,
- non_constant_p, overflow_p);
+ cond
+ = eval_constant_expression (ctx, cond, /*lval*/ false, non_constant_p,
+ overflow_p, jump_target);
VERIFY_CONSTANT (cond);
if (integer_nonzerop (cond))
*jump_target = t;
@@ -2225,7 +2305,8 @@ eval_constant_expression (const constexpr_ctx *ctx, tree t, bool lval,
else
{
r = eval_constant_expression (ctx, TREE_OPERAND (t, 0), false,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
if (*non_constant_p)
break;
ctx->global->values.put (t, r);
@@ -2239,7 +2320,7 @@ eval_constant_expression (const constexpr_ctx *ctx, tree t, bool lval,
tree oldop = TREE_OPERAND (t, 0);
tree op = eval_constant_expression (ctx, oldop,
/*lval*/ true, non_constant_p,
- overflow_p);
+ overflow_p, jump_target);
/* Don't VERIFY_CONSTANT here. */
if (*non_constant_p)
return t;
@@ -2284,7 +2365,8 @@ eval_constant_expression (const constexpr_ctx *ctx, tree t, bool lval,
if (lval)
{
r = eval_constant_expression (ctx, TREE_OPERAND (t, 0), lval,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
if (r == error_mark_node)
;
else if (r == TREE_OPERAND (t, 0))
@@ -2303,7 +2385,8 @@ eval_constant_expression (const constexpr_ctx *ctx, tree t, bool lval,
case BIT_NOT_EXPR:
case TRUTH_NOT_EXPR:
case FIXED_CONVERT_EXPR:
- r = eval_unary_expression (ctx, t, lval, non_constant_p, overflow_p);
+ r = eval_unary_expression (ctx, t, lval, non_constant_p, overflow_p,
+ jump_target);
break;
case LOOP_EXPR:
@@ -2318,7 +2401,8 @@ eval_constant_expression (const constexpr_ctx *ctx, tree t, bool lval,
break;
case ARRAY_REF:
- r = eval_array_reference (ctx, t, lval, non_constant_p, overflow_p);
+ r = eval_array_reference (ctx, t, lval, non_constant_p, overflow_p,
+ jump_target);
break;
case COMPONENT_REF:
@@ -2332,11 +2416,13 @@ eval_constant_expression (const constexpr_ctx *ctx, tree t, bool lval,
*non_constant_p = true;
return t;
}
- r = eval_component_reference (ctx, t, lval, non_constant_p, overflow_p);
+ r = eval_component_reference (ctx, t, lval, non_constant_p, overflow_p,
+ jump_target);
break;
case BIT_FIELD_REF:
- r = eval_bit_field_ref (ctx, t, lval, non_constant_p, overflow_p);
+ r = eval_bit_field_ref (ctx, t, lval, non_constant_p, overflow_p,
+ jump_target);
break;
case COND_EXPR:
@@ -2381,7 +2467,7 @@ eval_constant_expression (const constexpr_ctx *ctx, tree t, bool lval,
case VEC_COND_EXPR:
r = eval_vector_conditional_expression (ctx, t, non_constant_p,
- overflow_p);
+ overflow_p, jump_target);
break;
case TRY_CATCH_EXPR:
@@ -2407,7 +2493,7 @@ eval_constant_expression (const constexpr_ctx *ctx, tree t, bool lval,
/* Evaluate the cleanups. */
FOR_EACH_VEC_ELT_REVERSE (cleanups, i, cleanup)
eval_constant_expression (ctx, cleanup, false, non_constant_p,
- overflow_p);
+ overflow_p, jump_target);
}
break;
@@ -2417,7 +2503,7 @@ eval_constant_expression (const constexpr_ctx *ctx, tree t, bool lval,
if (!*non_constant_p)
/* Also evaluate the cleanup. */
eval_constant_expression (ctx, TREE_OPERAND (t, 1), true,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p, jump_target);
break;
case CONSTRUCTOR:
@@ -2429,7 +2515,8 @@ eval_constant_expression (const constexpr_ctx *ctx, tree t, bool lval,
if (TREE_CONSTANT (t))
return fold (t);
}
- r = eval_bare_aggregate (ctx, t, lval, non_constant_p, overflow_p);
+ r = eval_bare_aggregate (ctx, t, lval, non_constant_p, overflow_p,
+ jump_target);
break;
/* FALLTHROUGH. */
@@ -2440,7 +2527,7 @@ eval_constant_expression (const constexpr_ctx *ctx, tree t, bool lval,
tree oldop = TREE_OPERAND (t, 0);
tree op = eval_constant_expression (ctx, oldop, lval, non_constant_p,
- overflow_p);
+ overflow_p, jump_target);
if (*non_constant_p)
return t;
tree type = TREE_TYPE (t);
@@ -2571,7 +2658,7 @@ eval_constant_expression (const constexpr_ctx *ctx, tree t, bool lval,
return ctor;
else
return eval_constant_expression (ctx, ctor, lval, non_constant_p,
- overflow_p);
+ overflow_p, jump_target);
}
/* A placeholder without a referent. We can get here when
checking whether NSDMIs are noexcept, or in massage_init_elt;
@@ -2632,7 +2719,8 @@ is_empty_field (tree decl)
static tree
eval_store_expression (const constexpr_ctx *ctx, tree t, bool lval,
- bool *non_constant_p, bool *overflow_p)
+ bool *non_constant_p, bool *overflow_p,
+ tree *jump_target)
{
constexpr_ctx new_ctx = *ctx;
@@ -2653,7 +2741,7 @@ eval_store_expression (const constexpr_ctx *ctx, tree t, bool lval,
if (!SCALAR_TYPE_P (type))
new_ctx.ctor = new_ctx.object = NULL_TREE;
init = eval_constant_expression (&new_ctx, init, false, non_constant_p,
- overflow_p);
+ overflow_p, jump_target);
if (*non_constant_p)
return t;
}
@@ -2665,7 +2753,7 @@ eval_store_expression (const constexpr_ctx *ctx, tree t, bool lval,
as a whole; otherwise, only evaluate the innermost piece to avoid
building up unnecessary *_REFs. */
target = eval_constant_expression (ctx, target, true, non_constant_p,
- overflow_p);
+ overflow_p, jump_target);
evaluated = true;
if (*non_constant_p)
return t;
@@ -2694,7 +2782,8 @@ eval_store_expression (const constexpr_ctx *ctx, tree t, bool lval,
if (TREE_CODE (probe) == ARRAY_REF)
{
elt = eval_and_check_array_index (ctx, probe, false,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p,
+ jump_target);
if (*non_constant_p)
return t;
}
@@ -2718,8 +2807,9 @@ eval_store_expression (const constexpr_ctx *ctx, tree t, bool lval,
object = probe;
else
{
- probe = eval_constant_expression (ctx, probe, true,
- non_constant_p, overflow_p);
+ probe
+ = eval_constant_expression (ctx, probe, true, non_constant_p,
+ overflow_p, jump_target);
evaluated = true;
if (*non_constant_p)
return t;
@@ -2910,7 +3000,7 @@ eval_store_expression (const constexpr_ctx *ctx, tree t, bool lval,
if (tree tinit = TARGET_EXPR_INITIAL (init))
init = tinit;
init = eval_constant_expression (&new_ctx, init, false, non_constant_p,
- overflow_p);
+ overflow_p, jump_target);
/* The hash table might have moved since the get earlier, and the
initializer might have mutated the underlying CONSTRUCTORs, so we must
recompute VALP. */
@@ -3012,22 +3102,115 @@ eval_store_expression (const constexpr_ctx *ctx, tree t, bool lval,
Like cxx_eval_unary_expression, except for binary expressions. */
static tree
eval_binary_expression (const constexpr_ctx *ctx, tree t, bool lval,
- bool *non_constant_p, bool *overflow_p)
+ bool *non_constant_p, bool *overflow_p,
+ tree *jump_target)
{
+ tree r = NULL_TREE;
tree orig_lhs = TREE_OPERAND (t, 0);
tree orig_rhs = TREE_OPERAND (t, 1);
tree lhs, rhs;
-
lhs = eval_constant_expression (ctx, orig_lhs, lval, non_constant_p,
- overflow_p);
+ overflow_p, jump_target);
+ /* Don't VERIFY_CONSTANT here, it's unnecessary and will break pointer
+ subtraction. */
+ if (*non_constant_p)
+ return t;
+ if (*jump_target)
+ return NULL_TREE;
+
rhs = eval_constant_expression (ctx, orig_rhs, lval, non_constant_p,
- overflow_p);
+ overflow_p, jump_target);
+ if (*non_constant_p)
+ return t;
+ if (*jump_target)
+ return NULL_TREE;
location_t loc = EXPR_LOCATION (t);
enum tree_code code = TREE_CODE (t);
tree type = TREE_TYPE (t);
- return fold_binary_loc (loc, code, type, lhs, rhs);
+ if (code == EQ_EXPR || code == NE_EXPR)
+ {
+ bool is_code_eq = (code == EQ_EXPR);
+
+ if (TREE_CODE (lhs) == PTRMEM_CST && TREE_CODE (rhs) == PTRMEM_CST)
+ {
+ tree lmem = PTRMEM_CST_MEMBER (lhs);
+ tree rmem = PTRMEM_CST_MEMBER (rhs);
+ bool eq;
+ if (TREE_CODE (lmem) == TREE_CODE (rmem)
+ && TREE_CODE (lmem) == FIELD_DECL
+ && TREE_CODE (DECL_CONTEXT (lmem)) == UNION_TYPE
+ && same_type_p (DECL_CONTEXT (lmem), DECL_CONTEXT (rmem)))
+ /* If both refer to (possibly different) members of the same union
+ (12.3), they compare equal. */
+ eq = true;
+ // else
+ // eq = cp_tree_equal (lhs, rhs);
+ r = constant_boolean_node (eq == is_code_eq, type);
+ }
+ else if ((TREE_CODE (lhs) == PTRMEM_CST || TREE_CODE (rhs) == PTRMEM_CST)
+ && (null_member_pointer_value_p (lhs)
+ || null_member_pointer_value_p (rhs)))
+ r = constant_boolean_node (!is_code_eq, type);
+ }
+ if (r == NULL_TREE && TREE_CODE_CLASS (code) == tcc_comparison
+ && POINTER_TYPE_P (TREE_TYPE (lhs)))
+ {
+ if (tree lhso = maybe_fold_addr_pointer_plus (lhs))
+ lhs = fold_convert (TREE_TYPE (lhs), lhso);
+ if (tree rhso = maybe_fold_addr_pointer_plus (rhs))
+ rhs = fold_convert (TREE_TYPE (rhs), rhso);
+ }
+ if (code == POINTER_PLUS_EXPR && !*non_constant_p && integer_zerop (lhs)
+ && !integer_zerop (rhs))
+ {
+ if (!ctx->quiet)
+ error ("arithmetic involving a null pointer in %qE", lhs);
+ *non_constant_p = true;
+ return t;
+ }
+ else if (code == POINTER_PLUS_EXPR)
+ {
+ r = fold_pointer_plus_expression (ctx, t, lhs, rhs, non_constant_p,
+ overflow_p, jump_target);
+ if (*jump_target)
+ return NULL_TREE;
+ }
+
+ if (r == NULL_TREE)
+ {
+ r = fold_binary_loc (loc, code, type, lhs, rhs);
+ }
+
+ if (r == NULL_TREE && (code == LSHIFT_EXPR || code == RSHIFT_EXPR)
+ && TREE_CODE (lhs) == INTEGER_CST && TREE_CODE (rhs) == INTEGER_CST
+ && wi::neg_p (wi::to_wide (rhs)))
+ {
+ /* For diagnostics and -fpermissive emulate previous behavior of
+ handling shifts by negative amount. */
+ tree nrhs = const_unop (NEGATE_EXPR, TREE_TYPE (rhs), rhs);
+ if (nrhs)
+ r = fold_binary_loc (loc,
+ code == LSHIFT_EXPR ? RSHIFT_EXPR : LSHIFT_EXPR,
+ type, lhs, nrhs);
+ }
+
+ if (r == NULL_TREE)
+ {
+ if (lhs == orig_lhs && rhs == orig_rhs)
+ r = t;
+ else
+ r = build2_loc (loc, code, type, lhs, rhs);
+ }
+ else if (eval_check_shift_p (loc, ctx, code, type, lhs, rhs))
+ *non_constant_p = true;
+ /* Don't VERIFY_CONSTANT if this might be dealing with a pointer to
+ a local array in a constexpr function. */
+ bool ptr = INDIRECT_TYPE_P (TREE_TYPE (lhs));
+ if (!ptr)
+ VERIFY_CONSTANT (r);
+ return r;
}
/* Helper function of cxx_bind_parameters_in_call. Return non-NULL
@@ -3065,7 +3248,7 @@ addr_of_non_const_var (tree *tp, int *walk_subtrees, void *data)
static tree
rs_bind_parameters_in_call (const constexpr_ctx *ctx, tree t, tree fun,
bool *non_constant_p, bool *overflow_p,
- bool *non_constant_args)
+ bool *non_constant_args, tree *jump_target)
{
const int nargs = call_expr_nargs (t);
tree parms = DECL_ARGUMENTS (fun);
@@ -3089,7 +3272,7 @@ rs_bind_parameters_in_call (const constexpr_ctx *ctx, tree t, tree fun,
such as this, but here we do the elision differently: we keep the
TARGET_EXPR, and use its CONSTRUCTOR as the value of the parm. */
arg = eval_constant_expression (ctx, x, /*lval=*/false, non_constant_p,
- overflow_p);
+ overflow_p, jump_target);
/* Don't VERIFY_CONSTANT here. */
if (*non_constant_p && ctx->quiet)
break;
@@ -3155,7 +3338,8 @@ rs_bind_parameters_in_call (const constexpr_ctx *ctx, tree t, tree fun,
static tree
eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun,
- bool lval, bool *non_constant_p, bool *overflow_p)
+ bool lval, bool *non_constant_p, bool *overflow_p,
+ tree *jump_target)
{
const int nargs = call_expr_nargs (t);
tree *args = (tree *) alloca (nargs * sizeof (tree));
@@ -3258,8 +3442,9 @@ eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun,
|| potential_constant_expression (arg))
{
bool dummy1 = false, dummy2 = false;
- arg
- = eval_constant_expression (&new_ctx, arg, false, &dummy1, &dummy2);
+ tree dummy_jump_target = NULL_TREE;
+ arg = eval_constant_expression (&new_ctx, arg, false, &dummy1,
+ &dummy2, &dummy_jump_target);
}
if (bi_const_p)
@@ -3355,7 +3540,7 @@ eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun,
}
return eval_constant_expression (&new_ctx, new_call, lval, non_constant_p,
- overflow_p);
+ overflow_p, jump_target);
}
// Subroutine of cxx_eval_constant_expression.
@@ -3363,7 +3548,7 @@ eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun,
// evaluation.
static tree
eval_call_expression (const constexpr_ctx *ctx, tree t, bool lval,
- bool *non_constant_p, bool *overflow_p)
+ bool *non_constant_p, bool *overflow_p, tree *jump_target)
{
location_t loc = EXPR_LOCATION (t);
tree fun = get_function_named_in_call (t);
@@ -3392,12 +3577,12 @@ eval_call_expression (const constexpr_ctx *ctx, tree t, bool lval,
if (fndecl_built_in_p (fun))
return eval_builtin_function_call (ctx, t, fun, lval, non_constant_p,
- overflow_p);
+ overflow_p, jump_target);
bool non_constant_args = false;
new_call.bindings
= rs_bind_parameters_in_call (ctx, t, fun, non_constant_p, overflow_p,
- &non_constant_args);
+ &non_constant_args, jump_target);
/* We build up the bindings list before we know whether we already have this
call cached. If we don't end up saving these bindings, ggc_free them when
@@ -3960,7 +4145,7 @@ constexpr_fn_retval (const constexpr_ctx *ctx, tree body)
bool non_constant_p = false;
bool overflow_p = false;
return eval_constant_expression (ctx, body, false, &non_constant_p,
- &overflow_p);
+ &overflow_p, NULL);
}
case DECL_EXPR:
{
@@ -4024,6 +4209,17 @@ constant_value_1 (tree decl, bool, bool, bool unshare_p)
return unshare_p ? unshare_expr (decl) : decl;
}
+/* Like scalar_constant_value, but can also return aggregate initializers.
+ If UNSHARE_P, return an unshared copy of the initializer. */
+
+tree
+decl_really_constant_value (tree decl, bool unshare_p /*= true*/)
+{
+ return constant_value_1 (decl, /*strict_p=*/true,
+ /*return_aggregate_cst_ok_p=*/true,
+ /*unshare_p=*/unshare_p);
+}
+
// A more relaxed version of decl_really_constant_value, used by the
// common C/C++ code.
tree
@@ -4037,15 +4233,38 @@ decl_constant_value (tree decl, bool unshare_p)
static void
non_const_var_error (location_t loc, tree r)
{
- error_at (loc,
- "the value of %qD is not usable in a constant "
- "expression",
- r);
+ tree type = TREE_TYPE (r);
+
/* Avoid error cascade. */
if (DECL_INITIAL (r) == error_mark_node)
return;
-
- // more in cp/constexpr.cc
+ if (DECL_DECLARED_CONSTEXPR_P (r))
+ inform (DECL_SOURCE_LOCATION (r), "%qD used in its own initializer", r);
+ else if (INTEGRAL_OR_ENUMERATION_TYPE_P (type))
+ {
+ if (!DECL_INITIAL (r) || !TREE_CONSTANT (DECL_INITIAL (r))
+ || !DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (r))
+ inform (DECL_SOURCE_LOCATION (r),
+ "%qD was not initialized with a constant "
+ "expression",
+ r);
+ else
+ gcc_unreachable ();
+ }
+ else if (TYPE_REF_P (type))
+ inform (DECL_SOURCE_LOCATION (r),
+ "%qD was not initialized with a constant "
+ "expression",
+ r);
+ else
+ {
+ if (!DECL_DECLARED_CONSTEXPR_P (r))
+ inform (DECL_SOURCE_LOCATION (r), "%qD was not declared %<constexpr%>",
+ r);
+ else
+ inform (DECL_SOURCE_LOCATION (r),
+ "%qD does not have integral or enumeration type", r);
+ }
}
static tree
@@ -4322,7 +4541,7 @@ verify_constant (tree t, bool allow_non_constant, bool *non_constant_p,
if (!*non_constant_p && !reduced_constant_expression_p (t) && t != void_node)
{
if (!allow_non_constant)
- error ("%q+E is not a constant expression", t);
+ error_at (EXPR_LOCATION (t), "is not a constant expression");
*non_constant_p = true;
}
if (TREE_OVERFLOW_P (t))
@@ -4427,7 +4646,8 @@ diag_array_subscript (location_t loc, const constexpr_ctx *ctx, tree array,
static tree
get_array_or_vector_nelts (const constexpr_ctx *ctx, tree type,
- bool *non_constant_p, bool *overflow_p)
+ bool *non_constant_p, bool *overflow_p,
+ tree *jump_target)
{
tree nelts;
if (TREE_CODE (type) == ARRAY_TYPE)
@@ -4443,8 +4663,8 @@ get_array_or_vector_nelts (const constexpr_ctx *ctx, tree type,
rust_unreachable ();
/* For VLAs, the number of elements won't be an integer constant. */
- nelts
- = eval_constant_expression (ctx, nelts, false, non_constant_p, overflow_p);
+ nelts = eval_constant_expression (ctx, nelts, false, non_constant_p,
+ overflow_p, jump_target);
return nelts;
}
@@ -4456,13 +4676,13 @@ get_array_or_vector_nelts (const constexpr_ctx *ctx, tree type,
static tree
eval_and_check_array_index (const constexpr_ctx *ctx, tree t,
bool allow_one_past, bool *non_constant_p,
- bool *overflow_p)
+ bool *overflow_p, tree *jump_target)
{
location_t loc = rs_expr_loc_or_input_loc (t);
tree ary = TREE_OPERAND (t, 0);
t = TREE_OPERAND (t, 1);
tree index = eval_constant_expression (ctx, t, allow_one_past, non_constant_p,
- overflow_p);
+ overflow_p, jump_target);
VERIFY_CONSTANT (index);
if (!tree_fits_shwi_p (index) || tree_int_cst_sgn (index) < 0)
@@ -4473,7 +4693,7 @@ eval_and_check_array_index (const constexpr_ctx *ctx, tree t,
}
tree nelts = get_array_or_vector_nelts (ctx, TREE_TYPE (ary), non_constant_p,
- overflow_p);
+ overflow_p, jump_target);
VERIFY_CONSTANT (nelts);
if (allow_one_past ? !tree_int_cst_le (index, nelts)
: !tree_int_cst_lt (index, nelts))
@@ -4683,9 +4903,9 @@ eval_conditional_expression (const constexpr_ctx *ctx, tree t, bool lval,
bool *non_constant_p, bool *overflow_p,
tree *jump_target)
{
- tree val
- = eval_constant_expression (ctx, TREE_OPERAND (t, 0),
- /*lval*/ false, non_constant_p, overflow_p);
+ tree val = eval_constant_expression (ctx, TREE_OPERAND (t, 0),
+ /*lval*/ false, non_constant_p,
+ overflow_p, jump_target);
VERIFY_CONSTANT (val);
if (TREE_CODE (t) == IF_STMT && IF_STMT_CONSTEVAL_P (t))
{
@@ -4722,14 +4942,14 @@ eval_conditional_expression (const constexpr_ctx *ctx, tree t, bool lval,
static tree
eval_bit_field_ref (const constexpr_ctx *ctx, tree t, bool lval,
- bool *non_constant_p, bool *overflow_p)
+ bool *non_constant_p, bool *overflow_p, tree *jump_target)
{
tree orig_whole = TREE_OPERAND (t, 0);
tree retval, fldval, utype, mask;
bool fld_seen = false;
HOST_WIDE_INT istart, isize;
tree whole = eval_constant_expression (ctx, orig_whole, lval, non_constant_p,
- overflow_p);
+ overflow_p, jump_target);
tree start, field, value;
unsigned HOST_WIDE_INT i;
@@ -4960,8 +5180,8 @@ eval_switch_expr (const constexpr_ctx *ctx, tree t, bool *non_constant_p,
{
tree cond
= TREE_CODE (t) == SWITCH_STMT ? SWITCH_STMT_COND (t) : SWITCH_COND (t);
- cond
- = eval_constant_expression (ctx, cond, false, non_constant_p, overflow_p);
+ cond = eval_constant_expression (ctx, cond, false, non_constant_p, overflow_p,
+ jump_target);
VERIFY_CONSTANT (cond);
*jump_target = cond;
@@ -4995,12 +5215,13 @@ eval_switch_expr (const constexpr_ctx *ctx, tree t, bool *non_constant_p,
static tree
eval_unary_expression (const constexpr_ctx *ctx, tree t, bool /*lval*/,
- bool *non_constant_p, bool *overflow_p)
+ bool *non_constant_p, bool *overflow_p,
+ tree *jump_target)
{
tree r;
tree orig_arg = TREE_OPERAND (t, 0);
tree arg = eval_constant_expression (ctx, orig_arg, /*lval*/ false,
- non_constant_p, overflow_p);
+ non_constant_p, overflow_p, jump_target);
VERIFY_CONSTANT (arg);
location_t loc = EXPR_LOCATION (t);
enum tree_code code = TREE_CODE (t);
@@ -5136,7 +5357,9 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
if (manifestly_const_eval)
instantiate_constexpr_fns (r);
- r = eval_constant_expression (&ctx, r, false, &non_constant_p, &overflow_p);
+ tree jump_target = NULL_TREE;
+ r = eval_constant_expression (&ctx, r, false, &non_constant_p, &overflow_p,
+ &jump_target);
if (!constexpr_dtor)
verify_constant (r, allow_non_constant, &non_constant_p, &overflow_p);
@@ -5148,7 +5371,7 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
/* Evaluate the cleanups. */
FOR_EACH_VEC_ELT_REVERSE (cleanups, i, cleanup)
eval_constant_expression (&ctx, cleanup, false, &non_constant_p,
- &overflow_p);
+ &overflow_p, NULL);
/* Mutable logic is a bit tricky: we want to allow initialization of
constexpr variables with mutable members, but we can't copy those
@@ -5908,7 +6131,6 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
/* A pointer-to-member constant. */
return true;
- // handle_addr_expr:
#if 0
/* FIXME adjust when issue 1197 is fully resolved. For now don't do
any checking here, as we might dereference the pointer later. If
@@ -6484,6 +6706,170 @@ fold_non_dependent_init (tree t, tsubst_flags_t /*=tf_warning_or_error*/,
return maybe_constant_init (t, object, manifestly_const_eval);
}
+/* Check whether the shift operation with code CODE and type TYPE on LHS
+ and RHS is undefined. If it is, give an error with an explanation,
+ and return true; return false otherwise. */
+
+static bool
+eval_check_shift_p (location_t loc, const constexpr_ctx *ctx,
+ enum tree_code code, tree type, tree lhs, tree rhs)
+{
+ if ((code != LSHIFT_EXPR && code != RSHIFT_EXPR)
+ || TREE_CODE (lhs) != INTEGER_CST || TREE_CODE (rhs) != INTEGER_CST)
+ return false;
+
+ tree lhstype = TREE_TYPE (lhs);
+ unsigned HOST_WIDE_INT uprec = TYPE_PRECISION (TREE_TYPE (lhs));
+
+ /* [expr.shift] The behavior is undefined if the right operand
+ is negative, or greater than or equal to the length in bits
+ of the promoted left operand. */
+ if (tree_int_cst_sgn (rhs) == -1)
+ {
+ if (!ctx->quiet)
+ permerror (loc, "right operand of shift expression %q+E is negative",
+ build2_loc (loc, code, type, lhs, rhs));
+ return (!flag_permissive || ctx->quiet);
+ }
+ if (compare_tree_int (rhs, uprec) >= 0)
+ {
+ if (!ctx->quiet)
+ permerror (loc,
+ "right operand of shift expression %q+E is greater "
+ "than or equal to the precision %wu of the left operand",
+ build2_loc (loc, code, type, lhs, rhs), uprec);
+ return (!flag_permissive || ctx->quiet);
+ }
+
+ /* The value of E1 << E2 is E1 left-shifted E2 bit positions; [...]
+ if E1 has a signed type and non-negative value, and E1x2^E2 is
+ representable in the corresponding unsigned type of the result type,
+ then that value, converted to the result type, is the resulting value;
+ otherwise, the behavior is undefined.
+ For C++20:
+ The value of E1 << E2 is the unique value congruent to E1 x 2^E2 modulo
+ 2^N, where N is the range exponent of the type of the result. */
+ if (code == LSHIFT_EXPR && !TYPE_OVERFLOW_WRAPS (lhstype))
+ {
+ if (tree_int_cst_sgn (lhs) == -1)
+ {
+ if (!ctx->quiet)
+ permerror (loc, "left operand of shift expression %q+E is negative",
+ build2_loc (loc, code, type, lhs, rhs));
+ return (!flag_permissive || ctx->quiet);
+ }
+ /* For signed x << y the following:
+ (unsigned) x >> ((prec (lhs) - 1) - y)
+ if > 1, is undefined. The right-hand side of this formula
+ is the highest bit of the LHS that can be set (starting from 0),
+ so that the shift doesn't overflow. We then right-shift the LHS
+ to see whether any other bit is set making the original shift
+ undefined -- the result is not representable in the corresponding
+ unsigned type. */
+ tree t = build_int_cst (unsigned_type_node, uprec - 1);
+ t = fold_build2 (MINUS_EXPR, unsigned_type_node, t, rhs);
+ tree ulhs = fold_convert (unsigned_type_for (lhstype), lhs);
+ t = fold_build2 (RSHIFT_EXPR, TREE_TYPE (ulhs), ulhs, t);
+ if (tree_int_cst_lt (integer_one_node, t))
+ {
+ if (!ctx->quiet)
+ permerror (loc, "shift expression %q+E overflows",
+ build2_loc (loc, code, type, lhs, rhs));
+ return (!flag_permissive || ctx->quiet);
+ }
+ }
+ return false;
+}
+
+/* Helper function for cxx_eval_binary_expression. Try to optimize
+ original POINTER_PLUS_EXPR T, LHS p+ RHS, return NULL_TREE if the
+ generic folding should be used. */
+
+static tree
+fold_pointer_plus_expression (const constexpr_ctx *ctx, tree t, tree lhs,
+ tree rhs, bool *non_constant_p, bool *overflow_p,
+ tree *jump_target)
+{
+ STRIP_NOPS (lhs);
+ if (TREE_CODE (lhs) != ADDR_EXPR)
+ return NULL_TREE;
+
+ lhs = TREE_OPERAND (lhs, 0);
+
+ /* &A[i] p+ j => &A[i + j] */
+ if (TREE_CODE (lhs) == ARRAY_REF
+ && TREE_CODE (TREE_OPERAND (lhs, 1)) == INTEGER_CST
+ && TREE_CODE (rhs) == INTEGER_CST && TYPE_SIZE_UNIT (TREE_TYPE (lhs))
+ && TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (lhs))) == INTEGER_CST)
+ {
+ tree orig_type = TREE_TYPE (t);
+ location_t loc = EXPR_LOCATION (t);
+ tree type = TREE_TYPE (lhs);
+
+ t = fold_convert_loc (loc, ssizetype, TREE_OPERAND (lhs, 1));
+ tree nelts = array_type_nelts_top (TREE_TYPE (TREE_OPERAND (lhs, 0)));
+ nelts = eval_constant_expression (ctx, nelts, true, non_constant_p,
+ overflow_p, jump_target);
+ if (*non_constant_p)
+ return NULL_TREE;
+ if (*jump_target)
+ return NULL_TREE;
+ /* Don't fold an out-of-bound access. */
+ if (!tree_int_cst_le (t, nelts))
+ return NULL_TREE;
+ rhs = fold_convert (ssizetype, rhs);
+ /* Don't fold if rhs can't be divided exactly by TYPE_SIZE_UNIT.
+ constexpr int A[1]; ... (char *)&A[0] + 1 */
+ if (!integer_zerop (fold_build2_loc (loc, TRUNC_MOD_EXPR, sizetype, rhs,
+ TYPE_SIZE_UNIT (type))))
+ return NULL_TREE;
+ /* Make sure to treat the second operand of POINTER_PLUS_EXPR
+ as signed. */
+ rhs = fold_build2_loc (loc, EXACT_DIV_EXPR, ssizetype, rhs,
+ TYPE_SIZE_UNIT (type));
+ t = size_binop_loc (loc, PLUS_EXPR, rhs, t);
+ t = build4_loc (loc, ARRAY_REF, type, TREE_OPERAND (lhs, 0), t, NULL_TREE,
+ NULL_TREE);
+ t = build_fold_addr_expr (t);
+ t = fold_convert (orig_type, t);
+ return eval_constant_expression (ctx, t, true, non_constant_p, overflow_p,
+ jump_target);
+ }
+
+ return NULL_TREE;
+}
+
+/* Try to fold expressions like
+ (struct S *) (&a[0].D.2378 + 12)
+ into
+ &MEM <struct T> [(void *)&a + 12B]
+ This is something normally done by gimple_fold_stmt_to_constant_1
+ on GIMPLE, but is undesirable on GENERIC if we are e.g. going to
+ dereference the address because some details are lost.
+ For pointer comparisons we want such folding though so that
+ match.pd address_compare optimization works. */
+
+static tree
+maybe_fold_addr_pointer_plus (tree t)
+{
+ while (CONVERT_EXPR_P (t) && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (t, 0))))
+ t = TREE_OPERAND (t, 0);
+ if (TREE_CODE (t) != POINTER_PLUS_EXPR)
+ return NULL_TREE;
+ tree op0 = TREE_OPERAND (t, 0);
+ tree op1 = TREE_OPERAND (t, 1);
+ if (TREE_CODE (op1) != INTEGER_CST)
+ return NULL_TREE;
+ while (CONVERT_EXPR_P (op0)
+ && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (op0, 0))))
+ op0 = TREE_OPERAND (op0, 0);
+ if (TREE_CODE (op0) != ADDR_EXPR)
+ return NULL_TREE;
+ op1 = fold_convert (ptr_type_node, op1);
+ tree r = fold_build2 (MEM_REF, TREE_TYPE (TREE_TYPE (op0)), op0, op1);
+ return build1_loc (EXPR_LOCATION (t), ADDR_EXPR, TREE_TYPE (op0), r);
+}
+
} // namespace Compile
} // namespace Rust