Use colon instead of as to cast
This commit is contained in:
@ -43,6 +43,94 @@ namespace gcc
|
||||
this->symbol_map = symbol_table;
|
||||
}
|
||||
|
||||
void generic_visitor::build_procedure_call(location_t call_location,
|
||||
tree symbol, const std::vector<boot::expression *>& arguments)
|
||||
{
|
||||
vec<tree, va_gc> *argument_trees = nullptr;
|
||||
tree current_parameter = TYPE_ARG_TYPES(TREE_TYPE(symbol));
|
||||
|
||||
vec_alloc(argument_trees, arguments.size());
|
||||
for (boot::expression *const argument : arguments)
|
||||
{
|
||||
location_t argument_location = get_location(&argument->position());
|
||||
if (is_void_type(TREE_VALUE(current_parameter)))
|
||||
{
|
||||
error_at(argument_location, "too many arguments, expected %i, got %lu",
|
||||
list_length(TYPE_ARG_TYPES(TREE_TYPE(symbol))) - 1, arguments.size());
|
||||
this->current_expression = error_mark_node;
|
||||
break;
|
||||
}
|
||||
argument->accept(this);
|
||||
if (!is_assignable_from(TREE_VALUE(current_parameter), this->current_expression))
|
||||
{
|
||||
error_at(argument_location,
|
||||
"cannot assign value of type '%s' to variable of type '%s'",
|
||||
print_type(TREE_TYPE(this->current_expression)).c_str(),
|
||||
print_type(TREE_VALUE(current_parameter)).c_str());
|
||||
this->current_expression = error_mark_node;
|
||||
}
|
||||
current_parameter = TREE_CHAIN(current_parameter);
|
||||
argument_trees->quick_push(this->current_expression);
|
||||
}
|
||||
tree stmt = build_call_expr_loc_vec(call_location, symbol, argument_trees);
|
||||
|
||||
if (!is_void_type(TREE_VALUE(current_parameter)))
|
||||
{
|
||||
error_at(call_location, "too few arguments, expected %i, got %lu",
|
||||
list_length(TYPE_ARG_TYPES(TREE_TYPE(symbol))) - 1, arguments.size());
|
||||
this->current_expression = error_mark_node;
|
||||
}
|
||||
else if (TREE_TYPE(TREE_TYPE(symbol)) == void_type_node)
|
||||
{
|
||||
append_statement(stmt);
|
||||
this->current_expression = NULL_TREE;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->current_expression = stmt;
|
||||
}
|
||||
}
|
||||
|
||||
void generic_visitor::build_record_call(location_t call_location,
|
||||
tree symbol, const std::vector<boot::expression *>& arguments)
|
||||
{
|
||||
vec<constructor_elt, va_gc> *tree_arguments = nullptr;
|
||||
tree record_fields = TYPE_FIELDS(symbol);
|
||||
for (boot::expression *const argument : arguments)
|
||||
{
|
||||
location_t argument_location = get_location(&argument->position());
|
||||
|
||||
if (is_void_type(record_fields))
|
||||
{
|
||||
error_at(argument_location, "too many arguments, expected %i, got %lu",
|
||||
list_length(TYPE_FIELDS(symbol)), arguments.size());
|
||||
this->current_expression = error_mark_node;
|
||||
break;
|
||||
}
|
||||
argument->accept(this);
|
||||
if (!is_assignable_from(TREE_TYPE(record_fields), this->current_expression))
|
||||
{
|
||||
error_at(argument_location,
|
||||
"cannot assign value of type '%s' to variable of type '%s'",
|
||||
print_type(TREE_TYPE(this->current_expression)).c_str(),
|
||||
print_type(TREE_TYPE(record_fields)).c_str());
|
||||
this->current_expression = error_mark_node;
|
||||
}
|
||||
CONSTRUCTOR_APPEND_ELT(tree_arguments, record_fields, this->current_expression);
|
||||
record_fields = TREE_CHAIN(record_fields);
|
||||
}
|
||||
if (!is_void_type(record_fields))
|
||||
{
|
||||
error_at(call_location, "too few arguments, expected %i, got %lu",
|
||||
list_length(TYPE_FIELDS(symbol)), arguments.size());
|
||||
this->current_expression = error_mark_node;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->current_expression = build_constructor(symbol, tree_arguments);
|
||||
}
|
||||
}
|
||||
|
||||
void generic_visitor::visit(boot::call_expression *expression)
|
||||
{
|
||||
tree symbol = this->lookup(expression->name());
|
||||
@ -56,37 +144,11 @@ namespace gcc
|
||||
}
|
||||
else if (DECL_P(symbol) && is_procedure_type(TREE_TYPE(symbol)))
|
||||
{
|
||||
vec<tree, va_gc> *arguments = nullptr;
|
||||
|
||||
vec_alloc(arguments, expression->arguments().size());
|
||||
for (boot::expression *const argument : expression->arguments())
|
||||
{
|
||||
argument->accept(this);
|
||||
arguments->quick_push(this->current_expression);
|
||||
}
|
||||
tree stmt = build_call_expr_loc_vec(get_location(&expression->position()), symbol, arguments);
|
||||
|
||||
if (TREE_TYPE(TREE_TYPE(symbol)) == void_type_node)
|
||||
{
|
||||
append_statement(stmt);
|
||||
this->current_expression = NULL_TREE;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->current_expression = stmt;
|
||||
}
|
||||
build_procedure_call(call_location, symbol, expression->arguments());
|
||||
}
|
||||
else if (TYPE_P(symbol) && is_record_type(symbol))
|
||||
else if (TYPE_P(symbol) && TREE_CODE(symbol) == RECORD_TYPE)
|
||||
{
|
||||
vec<constructor_elt, va_gc> *arguments = nullptr;
|
||||
tree record_fields = TYPE_FIELDS(symbol);
|
||||
for (boot::expression *const argument : expression->arguments())
|
||||
{
|
||||
argument->accept(this);
|
||||
CONSTRUCTOR_APPEND_ELT(arguments, record_fields, this->current_expression);
|
||||
record_fields = TREE_CHAIN(record_fields);
|
||||
}
|
||||
this->current_expression = build_constructor(symbol, arguments);
|
||||
build_record_call(call_location, symbol, expression->arguments());
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -107,11 +169,9 @@ namespace gcc
|
||||
cast_target, this->current_expression);
|
||||
}
|
||||
|
||||
void generic_visitor::visit(boot::size_of_expression *expression)
|
||||
void generic_visitor::visit(boot::type_expression *expression)
|
||||
{
|
||||
auto body_type = build_type(expression->body());
|
||||
|
||||
this->current_expression = build1(CONVERT_EXPR, elna_word_type_node, size_in_bytes(body_type));
|
||||
this->current_expression = build_type(expression->body());
|
||||
}
|
||||
|
||||
void generic_visitor::visit(boot::program *program)
|
||||
@ -185,7 +245,7 @@ namespace gcc
|
||||
|
||||
for (std::size_t i = 0; i < definition->parameters.size(); ++i)
|
||||
{
|
||||
parameter_types[i] = build_type(definition->parameters.at(i)->type());
|
||||
parameter_types[i] = build_type(definition->parameters.at(i)->variable_type());
|
||||
}
|
||||
tree return_type = definition->return_type() == nullptr
|
||||
? void_type_node
|
||||
@ -315,12 +375,12 @@ namespace gcc
|
||||
|
||||
void generic_visitor::visit(boot::number_literal<std::int32_t> *literal)
|
||||
{
|
||||
this->current_expression = build_int_cst(elna_int_type_node, literal->number());
|
||||
this->current_expression = build_int_cst(elna_int_type_node, literal->value);
|
||||
}
|
||||
|
||||
void generic_visitor::visit(boot::number_literal<std::uint32_t> *literal)
|
||||
{
|
||||
this->current_expression = build_int_cstu(elna_word_type_node, literal->number());
|
||||
this->current_expression = build_int_cstu(elna_word_type_node, literal->value);
|
||||
}
|
||||
|
||||
void generic_visitor::visit(boot::number_literal<double> *literal)
|
||||
@ -329,7 +389,7 @@ namespace gcc
|
||||
|
||||
mpfr_t number;
|
||||
mpfr_init2(number, SIGNIFICAND_BITS);
|
||||
mpfr_set_d(number, literal->number(), MPFR_RNDN);
|
||||
mpfr_set_d(number, literal->value, MPFR_RNDN);
|
||||
|
||||
real_from_mpfr(&real_value1, number, double_type_node, MPFR_RNDN);
|
||||
|
||||
@ -340,12 +400,12 @@ namespace gcc
|
||||
|
||||
void generic_visitor::visit(boot::number_literal<bool> *boolean)
|
||||
{
|
||||
this->current_expression = boolean->number() ? boolean_true_node : boolean_false_node;
|
||||
this->current_expression = boolean->value ? boolean_true_node : boolean_false_node;
|
||||
}
|
||||
|
||||
void generic_visitor::visit(boot::number_literal<unsigned char> *character)
|
||||
{
|
||||
this->current_expression = build_int_cstu(elna_char_type_node, character->number());
|
||||
this->current_expression = build_int_cstu(elna_char_type_node, character->value);
|
||||
}
|
||||
|
||||
void generic_visitor::visit(boot::number_literal<nullptr_t> *)
|
||||
@ -355,10 +415,10 @@ namespace gcc
|
||||
|
||||
void generic_visitor::visit(boot::number_literal<std::string> *string)
|
||||
{
|
||||
tree index_constant = build_int_cstu(elna_word_type_node, string->number().size());
|
||||
tree index_constant = build_int_cstu(elna_word_type_node, string->value.size());
|
||||
tree string_type = build_array_type(elna_char_type_node, build_index_type(index_constant));
|
||||
|
||||
tree string_literal = build_string(string->number().size(), string->number().c_str());
|
||||
tree string_literal = build_string(string->value.size(), string->value.c_str());
|
||||
TREE_TYPE(string_literal) = string_type;
|
||||
TREE_CONSTANT(string_literal) = 1;
|
||||
TREE_READONLY(string_literal) = 1;
|
||||
@ -390,11 +450,49 @@ namespace gcc
|
||||
expression, operator_code, left, right, elna_bool_type_node);
|
||||
}
|
||||
|
||||
tree generic_visitor::build_logic_operation(boot::binary_expression *expression,
|
||||
tree_code operator_code, tree left, tree right)
|
||||
tree generic_visitor::build_bit_logic_operation(boot::binary_expression *expression, tree left, tree right)
|
||||
{
|
||||
return build_binary_operation(TREE_TYPE(left) == elna_bool_type_node,
|
||||
expression, operator_code, left, right, elna_bool_type_node);
|
||||
location_t expression_location = get_location(&expression->position());
|
||||
tree left_type = TREE_TYPE(left);
|
||||
tree right_type = TREE_TYPE(right);
|
||||
tree_code logical_code, bit_code;
|
||||
|
||||
if (expression->operation() == boot::binary_operator::conjunction)
|
||||
{
|
||||
bit_code = BIT_AND_EXPR;
|
||||
logical_code = TRUTH_ANDIF_EXPR;
|
||||
}
|
||||
else if (expression->operation() == boot::binary_operator::disjunction)
|
||||
{
|
||||
bit_code = BIT_IOR_EXPR;
|
||||
logical_code = TRUTH_ORIF_EXPR;
|
||||
}
|
||||
else if (expression->operation() == boot::binary_operator::exclusive_disjunction)
|
||||
{
|
||||
bit_code = BIT_XOR_EXPR;
|
||||
logical_code = TRUTH_XOR_EXPR;
|
||||
}
|
||||
else
|
||||
{
|
||||
gcc_unreachable();
|
||||
}
|
||||
|
||||
if (left_type == elna_bool_type_node)
|
||||
{
|
||||
return build2_loc(expression_location, logical_code, elna_bool_type_node, left, right);
|
||||
}
|
||||
else if (is_integral_type(left_type))
|
||||
{
|
||||
return build2_loc(expression_location, bit_code, left_type, left, right);
|
||||
}
|
||||
else
|
||||
{
|
||||
error_at(expression_location,
|
||||
"invalid operands of type '%s' and '%s' for operator %s",
|
||||
print_type(left_type).c_str(), print_type(right_type).c_str(),
|
||||
elna::boot::print_binary_operator(expression->operation()));
|
||||
return error_mark_node;
|
||||
}
|
||||
}
|
||||
|
||||
tree generic_visitor::build_equality_operation(boot::binary_expression *expression, tree left, tree right)
|
||||
@ -475,7 +573,9 @@ namespace gcc
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (left_type != right_type && !are_compatible_pointers(left, right) && !are_compatible_pointers(right, left))
|
||||
if (left_type != right_type
|
||||
&& !are_compatible_pointers(left_type, right)
|
||||
&& !are_compatible_pointers(right_type, left))
|
||||
{
|
||||
error_at(expression_location,
|
||||
"invalid operands of type %s and %s for operator %s",
|
||||
@ -514,10 +614,13 @@ namespace gcc
|
||||
this->current_expression = build_comparison_operation(expression, GE_EXPR, left, right);
|
||||
break;
|
||||
case boot::binary_operator::conjunction:
|
||||
this->current_expression = build_logic_operation(expression, TRUTH_ANDIF_EXPR, left, right);
|
||||
this->current_expression = build_bit_logic_operation(expression, left, right);
|
||||
break;
|
||||
case boot::binary_operator::disjunction:
|
||||
this->current_expression = build_logic_operation(expression, TRUTH_ORIF_EXPR, left, right);
|
||||
this->current_expression = build_bit_logic_operation(expression, left, right);
|
||||
break;
|
||||
case boot::binary_operator::exclusive_disjunction:
|
||||
this->current_expression = build_bit_logic_operation(expression, left, right);
|
||||
break;
|
||||
case boot::binary_operator::equals:
|
||||
this->current_expression = build_equality_operation(expression, left, right);
|
||||
@ -531,23 +634,47 @@ namespace gcc
|
||||
void generic_visitor::visit(boot::unary_expression *expression)
|
||||
{
|
||||
expression->operand().accept(this);
|
||||
location_t location = get_location(&expression->position());
|
||||
|
||||
switch (expression->operation())
|
||||
{
|
||||
case boot::unary_operator::reference:
|
||||
TREE_ADDRESSABLE(this->current_expression) = 1;
|
||||
this->current_expression = build_fold_addr_expr_with_type_loc(get_location(&expression->position()),
|
||||
this->current_expression = build_fold_addr_expr_with_type_loc(location,
|
||||
this->current_expression,
|
||||
build_pointer_type_for_mode(TREE_TYPE(this->current_expression), VOIDmode, true));
|
||||
TREE_NO_TRAMPOLINE(this->current_expression) = 1;
|
||||
break;
|
||||
case boot::unary_operator::negation:
|
||||
this->current_expression = build1_loc(get_location(&expression->position()), TRUTH_NOT_EXPR,
|
||||
boolean_type_node, this->current_expression);
|
||||
if (TREE_TYPE(this->current_expression) == elna_bool_type_node)
|
||||
{
|
||||
this->current_expression = build1_loc(location, TRUTH_NOT_EXPR,
|
||||
boolean_type_node, this->current_expression);
|
||||
}
|
||||
else if (is_integral_type(TREE_TYPE(this->current_expression)))
|
||||
{
|
||||
this->current_expression = build1_loc(location, BIT_NOT_EXPR,
|
||||
TREE_TYPE(this->current_expression), this->current_expression);
|
||||
}
|
||||
else
|
||||
{
|
||||
error_at(location, "type '%s' cannot be negated",
|
||||
print_type(TREE_TYPE(this->current_expression)).c_str());
|
||||
this->current_expression = error_mark_node;
|
||||
}
|
||||
break;
|
||||
case boot::unary_operator::minus:
|
||||
this->current_expression = fold_build1(NEGATE_EXPR, TREE_TYPE(this->current_expression),
|
||||
this->current_expression);
|
||||
if (is_integral_type(TREE_TYPE(this->current_expression)))
|
||||
{
|
||||
this->current_expression = fold_build1(NEGATE_EXPR, TREE_TYPE(this->current_expression),
|
||||
this->current_expression);
|
||||
}
|
||||
else
|
||||
{
|
||||
error_at(location, "type '%s' cannot be negated",
|
||||
print_type(TREE_TYPE(this->current_expression)).c_str());
|
||||
this->current_expression = error_mark_node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -603,9 +730,9 @@ namespace gcc
|
||||
}
|
||||
}
|
||||
|
||||
tree generic_visitor::build_type(boot::type_expression& type)
|
||||
tree generic_visitor::build_type(boot::top_type& type)
|
||||
{
|
||||
if (boot::basic_type_expression *basic_type = type.is_basic())
|
||||
if (boot::basic_type *basic_type = type.is_basic())
|
||||
{
|
||||
tree symbol = this->lookup(basic_type->base_name());
|
||||
|
||||
@ -618,7 +745,7 @@ namespace gcc
|
||||
|
||||
return error_mark_node;
|
||||
}
|
||||
else if (boot::array_type_expression *array_type = type.is_array())
|
||||
else if (boot::array_type *array_type = type.is_array())
|
||||
{
|
||||
tree lower_bound = build_int_cst_type(integer_type_node, 0);
|
||||
tree upper_bound = build_int_cst_type(integer_type_node, array_type->size);
|
||||
@ -632,7 +759,7 @@ namespace gcc
|
||||
|
||||
return build_array_type(base_type, range_type);
|
||||
}
|
||||
else if (boot::pointer_type_expression *pointer_type = type.is_pointer())
|
||||
else if (boot::pointer_type *pointer_type = type.is_pointer())
|
||||
{
|
||||
tree base_type = build_type(pointer_type->base());
|
||||
|
||||
@ -642,7 +769,7 @@ namespace gcc
|
||||
}
|
||||
return build_pointer_type_for_mode(base_type, VOIDmode, true);
|
||||
}
|
||||
else if (boot::record_type_expression *record_type = type.is_record())
|
||||
else if (boot::record_type *record_type = type.is_record())
|
||||
{
|
||||
std::set<std::string> field_names;
|
||||
tree record_type_node = make_node(RECORD_TYPE);
|
||||
@ -669,7 +796,7 @@ namespace gcc
|
||||
|
||||
return record_type_node;
|
||||
}
|
||||
else if (boot::union_type_expression *union_type = type.is_union())
|
||||
else if (boot::union_type *union_type = type.is_union())
|
||||
{
|
||||
std::set<std::string> field_names;
|
||||
tree union_type_node = make_node(UNION_TYPE);
|
||||
@ -701,7 +828,7 @@ namespace gcc
|
||||
|
||||
void generic_visitor::visit(boot::variable_declaration *declaration)
|
||||
{
|
||||
tree declaration_type = build_type(declaration->type());
|
||||
tree declaration_type = build_type(declaration->variable_type());
|
||||
gcc_assert(declaration_type != NULL_TREE);
|
||||
|
||||
location_t declaration_location = get_location(&declaration->position());
|
||||
@ -709,6 +836,10 @@ namespace gcc
|
||||
get_identifier(declaration->identifier.c_str()), declaration_type);
|
||||
bool result = this->symbol_map->enter(declaration->identifier, declaration_tree);
|
||||
|
||||
if (is_pointer_type(declaration_type))
|
||||
{
|
||||
DECL_INITIAL(declaration_tree) = elna_pointer_nil_node;
|
||||
}
|
||||
if (!result)
|
||||
{
|
||||
error_at(declaration_location, "variable '%s' already declared in this scope",
|
||||
@ -795,32 +926,56 @@ namespace gcc
|
||||
void generic_visitor::visit(boot::field_access_expression *expression)
|
||||
{
|
||||
expression->base().accept(this);
|
||||
tree field_declaration = TYPE_FIELDS(TREE_TYPE(this->current_expression));
|
||||
|
||||
while (field_declaration != NULL_TREE)
|
||||
{
|
||||
tree declaration_name = DECL_NAME(field_declaration);
|
||||
const char *identifier_pointer = IDENTIFIER_POINTER(declaration_name);
|
||||
|
||||
if (expression->field() == identifier_pointer)
|
||||
{
|
||||
break;
|
||||
}
|
||||
field_declaration = TREE_CHAIN(field_declaration);
|
||||
}
|
||||
location_t expression_location = get_location(&expression->position());
|
||||
if (field_declaration == NULL_TREE)
|
||||
|
||||
if (TYPE_P(this->current_expression))
|
||||
{
|
||||
error_at(expression_location,
|
||||
"record type does not have a field named '%s'",
|
||||
expression->field().c_str());
|
||||
this->current_expression = error_mark_node;
|
||||
if (expression->field() == "size")
|
||||
{
|
||||
this->current_expression = build1(CONVERT_EXPR, elna_word_type_node,
|
||||
size_in_bytes(this->current_expression));
|
||||
}
|
||||
else if (expression->field() == "alignment")
|
||||
{
|
||||
this->current_expression = build_int_cstu(elna_word_type_node,
|
||||
TYPE_ALIGN_UNIT(this->current_expression));
|
||||
}
|
||||
else
|
||||
{
|
||||
error_at(expression_location, "type '%s' does not have property '%s'",
|
||||
print_type(this->current_expression).c_str(), expression->field().c_str());
|
||||
this->current_expression = error_mark_node;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
else if (is_aggregate_type(TREE_TYPE(this->current_expression)))
|
||||
{
|
||||
this->current_expression = build3_loc(expression_location, COMPONENT_REF,
|
||||
TREE_TYPE(field_declaration), this->current_expression,
|
||||
field_declaration, NULL_TREE);
|
||||
tree field_declaration = TYPE_FIELDS(TREE_TYPE(this->current_expression));
|
||||
|
||||
while (field_declaration != NULL_TREE)
|
||||
{
|
||||
tree declaration_name = DECL_NAME(field_declaration);
|
||||
const char *identifier_pointer = IDENTIFIER_POINTER(declaration_name);
|
||||
|
||||
if (expression->field() == identifier_pointer)
|
||||
{
|
||||
break;
|
||||
}
|
||||
field_declaration = TREE_CHAIN(field_declaration);
|
||||
}
|
||||
if (field_declaration == NULL_TREE)
|
||||
{
|
||||
error_at(expression_location,
|
||||
"record type does not have a field named '%s'",
|
||||
expression->field().c_str());
|
||||
this->current_expression = error_mark_node;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->current_expression = build3_loc(expression_location, COMPONENT_REF,
|
||||
TREE_TYPE(field_declaration), this->current_expression,
|
||||
field_declaration, NULL_TREE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -848,8 +1003,7 @@ namespace gcc
|
||||
this->current_expression = error_mark_node;
|
||||
return;
|
||||
}
|
||||
if (TREE_TYPE(this->current_expression) == TREE_TYPE(lvalue)
|
||||
|| are_compatible_pointers(lvalue, this->current_expression))
|
||||
if (is_assignable_from(TREE_TYPE(lvalue), this->current_expression))
|
||||
{
|
||||
tree assignment = build2_loc(statement_location, MODIFY_EXPR,
|
||||
void_type_node, lvalue, this->current_expression);
|
||||
|
@ -62,20 +62,27 @@ namespace gcc
|
||||
return type == NULL_TREE || type == void_type_node;
|
||||
}
|
||||
|
||||
bool is_record_type(tree type)
|
||||
bool is_aggregate_type(tree type)
|
||||
{
|
||||
return TREE_CODE(type) == RECORD_TYPE;
|
||||
gcc_assert(TYPE_P(type));
|
||||
return TREE_CODE(type) == RECORD_TYPE || TREE_CODE(type) == UNION_TYPE;
|
||||
}
|
||||
|
||||
bool are_compatible_pointers(tree lhs, tree rhs)
|
||||
bool are_compatible_pointers(tree lhs_type, tree rhs)
|
||||
{
|
||||
tree lhs_type = TREE_TYPE(lhs);
|
||||
gcc_assert(TYPE_P(lhs_type));
|
||||
tree rhs_type = TREE_TYPE(rhs);
|
||||
|
||||
return (is_pointer_type(lhs_type) && rhs == elna_pointer_nil_node)
|
||||
|| (is_pointer_type(lhs_type) && lhs_type == rhs_type);
|
||||
}
|
||||
|
||||
bool is_assignable_from(tree assignee, tree assignment)
|
||||
{
|
||||
return TREE_TYPE(assignment) == assignee
|
||||
|| are_compatible_pointers(assignee, assignment);
|
||||
}
|
||||
|
||||
void append_statement(tree statement_tree)
|
||||
{
|
||||
if (!vec_safe_is_empty(f_binding_level->defers))
|
||||
|
Reference in New Issue
Block a user