From 6457a5ed61830fff5672943ea89e27b4c0a667b7 Mon Sep 17 00:00:00 2001 From: Daniel Kroening Date: Sun, 4 Aug 2019 15:57:55 +0100 Subject: [PATCH] fix exprt::opX() accesses in cpp/ This improves type safety. --- src/cpp/cpp_constructor.cpp | 6 +- src/cpp/cpp_static_assert.h | 7 +- src/cpp/cpp_typecheck.cpp | 2 +- src/cpp/cpp_typecheck_code.cpp | 52 +++--- src/cpp/cpp_typecheck_compound_type.cpp | 5 +- src/cpp/cpp_typecheck_constructor.cpp | 25 +-- src/cpp/cpp_typecheck_conversions.cpp | 21 +-- src/cpp/cpp_typecheck_expr.cpp | 215 ++++++++++++------------ src/cpp/cpp_typecheck_fargs.cpp | 4 +- src/cpp/cpp_typecheck_function.cpp | 6 +- src/cpp/cpp_typecheck_initializer.cpp | 19 ++- src/cpp/cpp_typecheck_resolve.cpp | 2 +- src/cpp/expr2cpp.cpp | 15 +- 13 files changed, 203 insertions(+), 176 deletions(-) diff --git a/src/cpp/cpp_constructor.cpp b/src/cpp/cpp_constructor.cpp index 71c77c0fa00..70041a0ea39 100644 --- a/src/cpp/cpp_constructor.cpp +++ b/src/cpp/cpp_constructor.cpp @@ -235,8 +235,10 @@ optionalt cpp_typecheckt::cpp_constructor( assert(initializer.id()==ID_code && initializer.get(ID_statement)==ID_expression); - side_effect_expr_function_callt &func_ini= - to_side_effect_expr_function_call(initializer.op0()); + auto &statement_expr = to_code_expression(to_code(initializer)); + + side_effect_expr_function_callt &func_ini = + to_side_effect_expr_function_call(statement_expr.expression()); exprt &tmp_this=func_ini.arguments().front(); DATA_INVARIANT( diff --git a/src/cpp/cpp_static_assert.h b/src/cpp/cpp_static_assert.h index be784ca51f1..7641549a37c 100644 --- a/src/cpp/cpp_static_assert.h +++ b/src/cpp/cpp_static_assert.h @@ -12,14 +12,13 @@ Author: Daniel Kroening, kroening@cs.cmu.edu #ifndef CPROVER_CPP_CPP_STATIC_ASSERT_H #define CPROVER_CPP_CPP_STATIC_ASSERT_H -#include +#include -class cpp_static_assertt:public exprt +class cpp_static_assertt : public binary_exprt { public: - cpp_static_assertt():exprt(ID_cpp_static_assert) + cpp_static_assertt() : binary_exprt(ID_cpp_static_assert) { - operands().resize(2); } exprt &cond() diff --git a/src/cpp/cpp_typecheck.cpp b/src/cpp/cpp_typecheck.cpp index e8163e38270..331805f27a1 100644 --- a/src/cpp/cpp_typecheck.cpp +++ b/src/cpp/cpp_typecheck.cpp @@ -243,7 +243,7 @@ void cpp_typecheckt::do_not_typechecked() } else if(symbol.value.operands().size()==1) { - value = symbol.value.op0(); + value = to_unary_expr(symbol.value).op(); cont=true; } else diff --git a/src/cpp/cpp_typecheck_code.cpp b/src/cpp/cpp_typecheck_code.cpp index cc4144682aa..af7d9616986 100644 --- a/src/cpp/cpp_typecheck_code.cpp +++ b/src/cpp/cpp_typecheck_code.cpp @@ -55,22 +55,29 @@ void cpp_typecheckt::typecheck_code(codet &code) // as an extension, we support indexed access into signed/unsigned // bitvectors, typically used with __CPROVER::(un)signedbv exprt &expr = code.op0(); - if( - expr.operands().size() == 2 && expr.op0().id() == ID_index && - expr.op0().operands().size() == 2) + + if(expr.operands().size() == 2) { - exprt array = expr.op0().op0(); - typecheck_expr(array); + auto &binary_expr = to_binary_expr(expr); - if(array.type().id() == ID_signedbv || array.type().id() == ID_unsignedbv) + if(binary_expr.op0().id() == ID_index) { - shl_exprt shl{from_integer(1, array.type()), expr.op0().op1()}; - exprt rhs = - if_exprt{equal_exprt{expr.op1(), from_integer(0, array.type())}, - bitand_exprt{array, bitnot_exprt{shl}}, - bitor_exprt{array, shl}}; - expr.op0() = expr.op0().op0(); - expr.op1() = rhs; + exprt array = to_index_expr(binary_expr.op0()).array(); + typecheck_expr(array); + + if( + array.type().id() == ID_signedbv || + array.type().id() == ID_unsignedbv) + { + shl_exprt shl{from_integer(1, array.type()), + to_index_expr(binary_expr.op0()).index()}; + exprt rhs = if_exprt{ + equal_exprt{binary_expr.op1(), from_integer(0, array.type())}, + bitand_exprt{array, bitnot_exprt{shl}}, + bitor_exprt{array, shl}}; + binary_expr.op0() = to_index_expr(binary_expr.op0()).array(); + binary_expr.op1() = rhs; + } } } @@ -191,8 +198,7 @@ void cpp_typecheckt::typecheck_switch(codet &code) assert(decl.operands().size()==1); // replace declaration by its symbol - assert(decl.op0().op0().id()==ID_symbol); - value = decl.op0().op0(); + value = to_code_decl(to_code(to_unary_expr(decl).op())).symbol(); c_typecheck_baset::typecheck_switch(code); @@ -287,11 +293,11 @@ void cpp_typecheckt::typecheck_member_initializer(codet &code) // a reference member if( symbol_expr.id() == ID_dereference && - symbol_expr.op0().id() == ID_member && + to_dereference_expr(symbol_expr).pointer().id() == ID_member && symbol_expr.get_bool(ID_C_implicit)) { // treat references as normal pointers - exprt tmp = symbol_expr.op0(); + exprt tmp = to_dereference_expr(symbol_expr).pointer(); symbol_expr.swap(tmp); } @@ -316,18 +322,20 @@ void cpp_typecheckt::typecheck_member_initializer(codet &code) if( symbol_expr.id() == ID_dereference && - symbol_expr.op0().id() == ID_member && + to_dereference_expr(symbol_expr).pointer().id() == ID_member && symbol_expr.get_bool(ID_C_implicit)) { // treat references as normal pointers - exprt tmp = symbol_expr.op0(); + exprt tmp = to_dereference_expr(symbol_expr).pointer(); symbol_expr.swap(tmp); } } - if(symbol_expr.id() == ID_member && - symbol_expr.op0().id() == ID_dereference && - symbol_expr.op0().op0() == cpp_scopes.current_scope().this_expr) + if( + symbol_expr.id() == ID_member && + to_member_expr(symbol_expr).op().id() == ID_dereference && + to_dereference_expr(to_member_expr(symbol_expr).op()).pointer() == + cpp_scopes.current_scope().this_expr) { if(is_reference(symbol_expr.type())) { diff --git a/src/cpp/cpp_typecheck_compound_type.cpp b/src/cpp/cpp_typecheck_compound_type.cpp index 056a91d83f0..d7e564b9ae9 100644 --- a/src/cpp/cpp_typecheck_compound_type.cpp +++ b/src/cpp/cpp_typecheck_compound_type.cpp @@ -1278,7 +1278,10 @@ void cpp_typecheckt::typecheck_member_function( } if(value.id() == ID_cpp_not_typechecked && value.has_operands()) - move_member_initializers(initializers, type, value.op0()); + { + move_member_initializers( + initializers, type, to_multi_ary_expr(value).op0()); + } else move_member_initializers(initializers, type, value); diff --git a/src/cpp/cpp_typecheck_constructor.cpp b/src/cpp/cpp_typecheck_constructor.cpp index d642c56e322..f8d45506536 100644 --- a/src/cpp/cpp_typecheck_constructor.cpp +++ b/src/cpp/cpp_typecheck_constructor.cpp @@ -68,10 +68,8 @@ static void copy_member( op1.copy_to_operands(cpp_namet(arg_name, source_location).as_expr()); op1.add_source_location()=source_location; - side_effect_exprt assign(ID_assign, typet(), source_location); - assign.copy_to_operands(op0.as_expr()); - assign.op0().add_source_location() = source_location; - assign.copy_to_operands(op1); + side_effect_expr_assignt assign(op0.as_expr(), op1, typet(), source_location); + assign.lhs().add_source_location() = source_location; code_expressiont code(assign); code.add_source_location() = source_location; @@ -102,13 +100,14 @@ static void copy_array( ID_component_cpp_name, cpp_namet(member_base_name, source_location)); member.copy_to_operands(cpp_namet(arg_name, source_location).as_expr()); - side_effect_exprt assign(ID_assign, typet(), source_location); + side_effect_expr_assignt assign( + index_exprt(array.as_expr(), constant), + index_exprt(member, constant), + typet(), + source_location); - assign.copy_to_operands(index_exprt(array.as_expr(), constant)); - assign.op0().add_source_location() = source_location; - - assign.copy_to_operands(index_exprt(member, constant)); - assign.op1().add_source_location() = source_location; + assign.lhs().add_source_location() = source_location; + assign.rhs().add_source_location() = source_location; code_expressiont code(assign); code.add_source_location() = source_location; @@ -186,7 +185,8 @@ void cpp_typecheckt::default_cpctor( irept &initializers=decl0.add(ID_member_initializers); initializers.id(ID_member_initializers); - cpp_declaratort &declarator=static_cast(cpctor.op0()); + cpp_declaratort &declarator = + static_cast(to_multi_ary_expr(cpctor).op0()); exprt &block=declarator.value(); // First, we need to call the parent copy constructors @@ -295,7 +295,8 @@ void cpp_typecheckt::default_assignop( cpctor.operands().push_back(exprt(ID_cpp_declarator)); cpctor.add_source_location()=source_location; - cpp_declaratort &declarator=(cpp_declaratort&) cpctor.op0(); + cpp_declaratort &declarator = + static_cast(to_multi_ary_expr(cpctor).op0()); declarator.add_source_location()=source_location; cpp_namet &declarator_name=declarator.name(); diff --git a/src/cpp/cpp_typecheck_conversions.cpp b/src/cpp/cpp_typecheck_conversions.cpp index d17860ffbeb..91d755f424e 100644 --- a/src/cpp/cpp_typecheck_conversions.cpp +++ b/src/cpp/cpp_typecheck_conversions.cpp @@ -894,7 +894,7 @@ bool cpp_typecheckt::user_defined_conversion_sequence( // simplify address if(expr.id()==ID_dereference) - address=expr.op0(); + address = to_dereference_expr(expr).pointer(); pointer_typet ptr_sub=pointer_type(type); c_qualifierst qual_from; @@ -1333,10 +1333,11 @@ bool cpp_typecheckt::reference_binding( reference_compatible(returned_value, type, rank)) { // returned values are lvalues in case of references only - assert(returned_value.id()==ID_dereference && - is_reference(returned_value.op0().type())); + DATA_INVARIANT( + is_reference(to_dereference_expr(returned_value).op().type()), + "the returned value must be pointer to reference"); - new_expr=returned_value.op0(); + new_expr = to_multi_ary_expr(returned_value).op0(); if(returned_value.type() != type.subtype()) { @@ -1484,7 +1485,7 @@ void cpp_typecheckt::implicit_typecast(exprt &expr, const typet &type) e.id() == ID_initializer_list && cpp_is_pod(type) && e.operands().size() == 1) { - e = expr.op0(); + e = to_unary_expr(expr).op(); } if(!implicit_conversion_sequence(e, type, expr)) @@ -1696,7 +1697,7 @@ bool cpp_typecheckt::dynamic_typecast( if(type.id()==ID_pointer) { if(e.id()==ID_dereference && e.get_bool(ID_C_implicit)) - e=expr.op0(); + e = to_dereference_expr(expr).pointer(); if(e.type().id()==ID_pointer && cast_away_constness(e.type(), type)) @@ -1749,7 +1750,7 @@ bool cpp_typecheckt::reinterpret_typecast( if(check_constantness && type.id()==ID_pointer) { if(e.id()==ID_dereference && e.get_bool(ID_C_implicit)) - e=expr.op0(); + e = to_dereference_expr(expr).pointer(); if(e.type().id()==ID_pointer && cast_away_constness(e.type(), type)) @@ -1845,7 +1846,7 @@ bool cpp_typecheckt::static_typecast( if(check_constantness && type.id()==ID_pointer) { if(e.id()==ID_dereference && e.get_bool(ID_C_implicit)) - e=expr.op0(); + e = to_dereference_expr(expr).pointer(); if(e.type().id()==ID_pointer && cast_away_constness(e.type(), type)) @@ -1884,8 +1885,8 @@ bool cpp_typecheckt::static_typecast( { if(e.id()==ID_dereference) { - make_ptr_typecast(e.op0(), type); - new_expr.swap(e.op0()); + make_ptr_typecast(to_dereference_expr(e).pointer(), type); + new_expr.swap(to_dereference_expr(e).pointer()); return true; } diff --git a/src/cpp/cpp_typecheck_expr.cpp b/src/cpp/cpp_typecheck_expr.cpp index b4e6f1d96d3..ec583ed71fa 100644 --- a/src/cpp/cpp_typecheck_expr.cpp +++ b/src/cpp/cpp_typecheck_expr.cpp @@ -363,10 +363,10 @@ void cpp_typecheckt::typecheck_function_expr( else if(expr.id()==ID_ptrmember) { typecheck_expr_operands(expr); - add_implicit_dereference(expr.op0()); + add_implicit_dereference(to_unary_expr(expr).op()); // is operator-> overloaded? - if(expr.op0().type().id() != ID_pointer) + if(to_unary_expr(expr).op().type().id() != ID_pointer) { std::string op_name="operator->"; @@ -376,7 +376,7 @@ void cpp_typecheckt::typecheck_function_expr( side_effect_expr_function_callt function_call( cpp_name.as_expr(), - {expr.op0()}, + {to_unary_expr(expr).op()}, uninitialized_typet{}, expr.source_location()); function_call.arguments().reserve(expr.operands().size()); @@ -385,7 +385,7 @@ void cpp_typecheckt::typecheck_function_expr( already_typechecked_exprt::make_already_typechecked(function_call); - expr.op0().swap(function_call); + to_unary_expr(expr).op().swap(function_call); typecheck_function_expr(expr, fargs); return; } @@ -479,7 +479,7 @@ bool cpp_typecheckt::operator_is_overloaded(exprt &expr) // See if the struct declares the cast operator as a member bool found_in_struct=false; assert(!expr.operands().empty()); - typet t0(follow(expr.op0().type())); + typet t0(follow(to_unary_expr(expr).op().type())); if(t0.id()==ID_struct) { @@ -499,7 +499,8 @@ bool cpp_typecheckt::operator_is_overloaded(exprt &expr) exprt member(ID_member); member.add(ID_component_cpp_name) = cpp_name; - member.copy_to_operands(already_typechecked_exprt{expr.op0()}); + member.copy_to_operands( + already_typechecked_exprt{to_unary_expr(expr).op()}); side_effect_expr_function_callt function_call( std::move(member), {}, uninitialized_typet{}, expr.source_location()); @@ -520,7 +521,7 @@ bool cpp_typecheckt::operator_is_overloaded(exprt &expr) { add_implicit_dereference(function_call); already_typechecked_exprt::make_already_typechecked(function_call); - expr.op0().swap(function_call); + to_unary_expr(expr).op().swap(function_call); typecheck_expr(expr); return true; } @@ -532,6 +533,7 @@ bool cpp_typecheckt::operator_is_overloaded(exprt &expr) for(const operator_entryt *e=operators; !e->id.empty(); e++) + { if(expr.id()==e->id) { if(expr.id()==ID_dereference) @@ -556,11 +558,11 @@ bool cpp_typecheckt::operator_is_overloaded(exprt &expr) // TODO: need to resolve an incomplete struct (template) here // go into scope of first operand if( - expr.op0().type().id() == ID_struct_tag && - follow(expr.op0().type()).id() == ID_struct) + to_multi_ary_expr(expr).op0().type().id() == ID_struct_tag && + follow(to_multi_ary_expr(expr).op0().type()).id() == ID_struct) { - const irep_idt &struct_identifier= - expr.op0().type().get(ID_identifier); + const irep_idt &struct_identifier = + to_multi_ary_expr(expr).op0().type().get(ID_identifier); // get that scope cpp_save_scopet save_scope(cpp_scopes); @@ -582,7 +584,8 @@ bool cpp_typecheckt::operator_is_overloaded(exprt &expr) exprt member(ID_member); member.add(ID_component_cpp_name) = cpp_name; - member.copy_to_operands(already_typechecked_exprt{expr.op0()}); + member.copy_to_operands( + already_typechecked_exprt{to_multi_ary_expr(expr).op0()}); side_effect_expr_function_callt function_call( std::move(member), @@ -639,7 +642,7 @@ bool cpp_typecheckt::operator_is_overloaded(exprt &expr) { add_implicit_dereference(function_call); already_typechecked_exprt::make_already_typechecked(function_call); - expr.op0() = function_call; + to_multi_ary_expr(expr).op0() = function_call; typecheck_expr(expr); return true; } @@ -650,6 +653,7 @@ bool cpp_typecheckt::operator_is_overloaded(exprt &expr) } } } + } return false; } @@ -663,7 +667,7 @@ void cpp_typecheckt::typecheck_expr_address_of(exprt &expr) throw 0; } - exprt &op=expr.op0(); + exprt &op = to_address_of_expr(expr).op(); if(!op.get_bool(ID_C_lvalue) && expr.type().id()==ID_code) { @@ -672,18 +676,17 @@ void cpp_typecheckt::typecheck_expr_address_of(exprt &expr) throw 0; } - if(expr.op0().type().id()==ID_code) + if(op.type().id() == ID_code) { // we take the address of the method. - assert(expr.op0().id()==ID_member); - exprt symb=cpp_symbol_expr(lookup(expr.op0().get(ID_component_name))); + DATA_INVARIANT(op.id() == ID_member, "address-of code must be a member"); + exprt symb = cpp_symbol_expr(lookup(op.get(ID_component_name))); address_of_exprt address(symb, pointer_type(symb.type())); address.set(ID_C_implicit, true); - expr.op0().swap(address); + op.swap(address); } - if(expr.op0().id()==ID_address_of && - expr.op0().get_bool(ID_C_implicit)) + if(op.id() == ID_address_of && op.get_bool(ID_C_implicit)) { // must be the address of a function code_typet &code_type=to_code_type(op.type().subtype()); @@ -693,7 +696,7 @@ void cpp_typecheckt::typecheck_expr_address_of(exprt &expr) { // it's a pointer to member function const struct_tag_typet symbol(code_type.get(ID_C_member_name)); - expr.op0().type().add(ID_to_member) = symbol; + op.type().add(ID_to_member) = symbol; if(code_type.get_bool(ID_C_is_virtual)) { @@ -704,11 +707,10 @@ void cpp_typecheckt::typecheck_expr_address_of(exprt &expr) } } } - else if( - expr.op0().id() == ID_ptrmember && expr.op0().op0().id() == "cpp-this") + else if(op.id() == ID_ptrmember && to_unary_expr(op).op().id() == "cpp-this") { - expr.type() = pointer_type(expr.op0().type()); - expr.type().add(ID_to_member) = expr.op0().op0().type().subtype(); + expr.type() = pointer_type(op.type()); + expr.type().add(ID_to_member) = to_unary_expr(op).op().type().subtype(); return; } @@ -729,11 +731,11 @@ void cpp_typecheckt::typecheck_expr_throw(exprt &expr) if(expr.operands().size()==1) { // nothing really to do; one can throw _almost_ anything - const typet &exception_type=expr.op0().type(); + const typet &exception_type = to_unary_expr(expr).op().type(); if(exception_type.id() == ID_empty) { - error().source_location=expr.op0().find_source_location(); + error().source_location = to_unary_expr(expr).op().find_source_location(); error() << "cannot throw void" << eom; throw 0; } @@ -795,7 +797,8 @@ void cpp_typecheckt::typecheck_expr_new(exprt &expr) if(!initializer.operands().empty() && expr.get(ID_statement)==ID_cpp_new_array) { - error().source_location=expr.op0().find_source_location(); + error().source_location = + to_multi_ary_expr(expr).op0().find_source_location(); error() << "new with array type must not use initializer" << eom; throw 0; } @@ -827,8 +830,8 @@ static exprt collect_comma_expression(const exprt &src) if(src.id()==ID_comma) { assert(src.operands().size()==2); - result=collect_comma_expression(src.op0()); - result.copy_to_operands(src.op1()); + result = collect_comma_expression(to_binary_expr(src).op0()); + result.copy_to_operands(to_binary_expr(src).op1()); } else result.copy_to_operands(src); @@ -859,6 +862,8 @@ void cpp_typecheckt::typecheck_expr_explicit_typecast(exprt &expr) } else if(expr.operands().size()==1) { + auto &op = to_unary_expr(expr).op(); + // Explicitly given value, e.g., int(1). // There is an expr-vs-type ambiguity, as it is possible to write // (f)(1), where 'f' is a function symbol and not a type. @@ -884,7 +889,7 @@ void cpp_typecheckt::typecheck_expr_explicit_typecast(exprt &expr) // become a comma expression, and that these are already typechecked. side_effect_expr_function_callt f_call( static_cast(static_cast(expr.type())), - collect_comma_expression(expr.op0()).operands(), + collect_comma_expression(op).operands(), uninitialized_typet{}, expr.source_location()); @@ -900,17 +905,17 @@ void cpp_typecheckt::typecheck_expr_explicit_typecast(exprt &expr) // We allow (TYPE){ initializer_list } // This is called "compound literal", and is syntactic // sugar for a (possibly local) declaration. - if(expr.op0().id()==ID_initializer_list) + if(op.id() == ID_initializer_list) { // just do a normal initialization - do_initializer(expr.op0(), expr.type(), false); + do_initializer(op, expr.type(), false); // This produces a struct-expression, // union-expression, array-expression, // or an expression for a pointer or scalar. // We produce a compound_literal expression. exprt tmp(ID_compound_literal, expr.type()); - tmp.add_to_operands(std::move(expr.op0())); + tmp.add_to_operands(std::move(op)); expr=tmp; expr.set(ID_C_lvalue, true); // these are l-values return; @@ -918,9 +923,10 @@ void cpp_typecheckt::typecheck_expr_explicit_typecast(exprt &expr) exprt new_expr; - if(const_typecast(expr.op0(), expr.type(), new_expr) || - static_typecast(expr.op0(), expr.type(), new_expr, false) || - reinterpret_typecast(expr.op0(), expr.type(), new_expr, false)) + if( + const_typecast(op, expr.type(), new_expr) || + static_typecast(op, expr.type(), new_expr, false) || + reinterpret_typecast(op, expr.type(), new_expr, false)) { expr=new_expr; add_implicit_dereference(expr); @@ -929,7 +935,7 @@ void cpp_typecheckt::typecheck_expr_explicit_typecast(exprt &expr) { error().source_location=expr.find_source_location(); error() << "invalid explicit cast:\n" - << "operand type: '" << to_string(expr.op0().type()) << "'\n" + << "operand type: '" << to_string(op.type()) << "'\n" << "casting to: '" << to_string(expr.type()) << "'" << eom; throw 0; } @@ -1002,7 +1008,7 @@ void cpp_typecheckt::typecheck_expr_delete(exprt &expr) else UNREACHABLE; - typet pointer_type = expr.op0().type(); + typet pointer_type = to_unary_expr(expr).op().type(); if(pointer_type.id()!=ID_pointer) { @@ -1059,7 +1065,7 @@ void cpp_typecheckt::typecheck_expr_member( throw 0; } - exprt &op0=expr.op0(); + exprt &op0 = to_unary_expr(expr).op(); add_implicit_dereference(op0); // The notation for explicit calls to destructors can be used regardless @@ -1127,7 +1133,7 @@ void cpp_typecheckt::typecheck_expr_member( if(symbol_expr.id()==ID_dereference) { assert(symbol_expr.get_bool(ID_C_implicit)); - exprt tmp=symbol_expr.op0(); + exprt tmp = to_dereference_expr(symbol_expr).pointer(); symbol_expr.swap(tmp); } @@ -1189,16 +1195,12 @@ void cpp_typecheckt::typecheck_expr_member( component.make_nil(); PRECONDITION( - expr.op0().type().id() == ID_struct || expr.op0().type().id() == ID_union || - expr.op0().type().id() == ID_struct_tag || - expr.op0().type().id() == ID_union_tag); + op0.type().id() == ID_struct || op0.type().id() == ID_union || + op0.type().id() == ID_struct_tag || op0.type().id() == ID_union_tag); exprt member; - if(get_component(expr.source_location(), - expr.op0(), - component_name, - member)) + if(get_component(expr.source_location(), op0, component_name, member)) { // because of possible anonymous members expr.swap(member); @@ -1240,20 +1242,20 @@ void cpp_typecheckt::typecheck_expr_ptrmember( throw 0; } - add_implicit_dereference(expr.op0()); + auto &op = to_unary_expr(expr).op(); - if(expr.op0().type().id()!=ID_pointer) + add_implicit_dereference(op); + + if(op.type().id() != ID_pointer) { error().source_location=expr.find_source_location(); error() << "error: ptrmember operator requires pointer type " - << "on left hand side, but got '" << to_string(expr.op0().type()) - << "'" << eom; + << "on left hand side, but got '" << to_string(op.type()) << "'" + << eom; throw 0; } exprt tmp; - exprt &op=expr.op0(); - op.swap(tmp); op.id(ID_dereference); @@ -1433,8 +1435,9 @@ void cpp_typecheckt::typecheck_expr_cpp_name( if(symbol_expr.id()==ID_member) { - if(symbol_expr.operands().empty() || - symbol_expr.op0().is_nil()) + if( + symbol_expr.operands().empty() || + to_multi_ary_expr(symbol_expr).op0().is_nil()) { if(to_code_type(symbol_expr.type()).return_type().id() != ID_constructor) { @@ -1590,24 +1593,23 @@ void cpp_typecheckt::typecheck_side_effect_function_call( } // do implicit dereference - if(expr.function().id()==ID_address_of && - expr.function().operands().size()==1) + if(expr.function().id() == ID_address_of) { exprt tmp; - tmp.swap(expr.function().op0()); + tmp.swap(to_address_of_expr(expr.function()).object()); expr.function().swap(tmp); } else { assert(expr.function().type().id()==ID_pointer); dereference_exprt tmp(expr.function()); - tmp.add_source_location()=expr.op0().source_location(); + tmp.add_source_location() = expr.function().source_location(); expr.function().swap(tmp); } if(expr.function().type().id()!=ID_code) { - error().source_location=expr.op0().find_source_location(); + error().source_location = expr.function().find_source_location(); error() << "expecting code as argument" << eom; throw 0; } @@ -1620,7 +1622,7 @@ void cpp_typecheckt::typecheck_side_effect_function_call( if(op0.id()==ID_member || op0.id()==ID_ptrmember) { vtptr_member.id(op0.id()); - vtptr_member.add_to_operands(std::move(op0.op0())); + vtptr_member.add_to_operands(std::move(to_unary_expr(op0).op())); } else { @@ -1659,7 +1661,7 @@ void cpp_typecheckt::typecheck_side_effect_function_call( { dereference_exprt tmp(vtentry_member); - tmp.add_source_location()=expr.op0().source_location(); + tmp.add_source_location() = expr.function().source_location(); vtentry_member.swap(tmp); } @@ -1697,8 +1699,8 @@ void cpp_typecheckt::typecheck_side_effect_function_call( { error().source_location=expr.function().find_source_location(); error() << "function call expects function or function " - << "pointer as argument, but got '" << to_string(expr.op0().type()) - << "'" << eom; + << "pointer as argument, but got '" + << to_string(expr.function().type()) << "'" << eom; throw 0; } @@ -1976,7 +1978,7 @@ void cpp_typecheckt::typecheck_method_application( } else { - exprt this_arg=member_expr.op0(); + exprt this_arg = to_member_expr(member_expr).compound(); implicit_typecast(this_arg, this_type); assert(is_reference(this_arg.type())); this_arg.type().remove(ID_C_reference); @@ -2002,7 +2004,7 @@ void cpp_typecheckt::typecheck_side_effect_assignment(side_effect_exprt &expr) throw 0; } - typet type0=expr.op0().type(); + typet type0 = to_binary_expr(expr).op0().type(); if(is_reference(type0)) type0=type0.subtype(); @@ -2012,7 +2014,7 @@ void cpp_typecheckt::typecheck_side_effect_assignment(side_effect_exprt &expr) // for structs we use the 'implicit assignment operator', // and therefore, it is allowed to assign to a rvalue struct. if(type0.id() == ID_struct_tag) - expr.op0().set(ID_C_lvalue, true); + to_binary_expr(expr).op0().set(ID_C_lvalue, true); c_typecheck_baset::typecheck_side_effect_assignment(expr); @@ -2061,11 +2063,11 @@ void cpp_typecheckt::typecheck_side_effect_assignment(side_effect_exprt &expr) // expr.op0() is already typechecked exprt member(ID_member); member.set(ID_component_cpp_name, cpp_name); - member.add_to_operands(already_typechecked_exprt{expr.op0()}); + member.add_to_operands(already_typechecked_exprt{to_binary_expr(expr).op0()}); side_effect_expr_function_callt new_expr( std::move(member), - {expr.op1()}, + {to_binary_expr(expr).op1()}, uninitialized_typet{}, expr.source_location()); @@ -2085,9 +2087,11 @@ void cpp_typecheckt::typecheck_side_effect_inc_dec( throw 0; } - add_implicit_dereference(expr.op0()); + auto &op = to_unary_expr(expr).op(); - const typet &tmp_type = expr.op0().type(); + add_implicit_dereference(op); + + const typet &tmp_type = op.type(); if(is_number(tmp_type) || tmp_type.id()==ID_pointer) @@ -2128,7 +2132,7 @@ void cpp_typecheckt::typecheck_side_effect_inc_dec( exprt member(ID_member); member.set(ID_component_cpp_name, cpp_name); - member.add_to_operands(already_typechecked_exprt{expr.op0()}); + member.add_to_operands(already_typechecked_exprt{op}); side_effect_expr_function_callt new_expr( std::move(member), {}, uninitialized_typet{}, expr.source_location()); @@ -2151,7 +2155,7 @@ void cpp_typecheckt::typecheck_expr_dereference(exprt &expr) throw 0; } - exprt &op=expr.op0(); + exprt &op = to_dereference_expr(expr).pointer(); const typet &op_type = op.type(); if(op_type.id() == ID_pointer && op_type.find(ID_to_member).is_not_nil()) @@ -2170,19 +2174,19 @@ void cpp_typecheckt::convert_pmop(exprt &expr) PRECONDITION(expr.id() == ID_pointer_to_member); PRECONDITION(expr.operands().size() == 2); - if( - expr.op1().type().id() != ID_pointer || - expr.op1().type().find(ID_to_member).is_nil()) + auto &op0 = to_binary_expr(expr).op0(); + auto &op1 = to_binary_expr(expr).op1(); + + if(op1.type().id() != ID_pointer || op1.type().find(ID_to_member).is_nil()) { error().source_location=expr.source_location(); error() << "pointer-to-member expected" << eom; throw 0; } - typet t0=expr.op0().type().id()==ID_pointer ? - expr.op0().type().subtype(): expr.op0().type(); + typet t0 = op0.type().id() == ID_pointer ? op0.type().subtype() : op0.type(); - typet t1((const typet &)expr.op1().type().find(ID_to_member)); + typet t1((const typet &)op1.type().find(ID_to_member)); t0=follow(t0); t1=follow(t1); @@ -2204,24 +2208,25 @@ void cpp_typecheckt::convert_pmop(exprt &expr) throw 0; } - typecheck_expr_main(expr.op1()); + typecheck_expr_main(op1); - if(expr.op0().type().id()!=ID_pointer) + if(op0.type().id() != ID_pointer) { - if(expr.op0().id()==ID_dereference) + if(op0.id() == ID_dereference) { - exprt tmp=expr.op0().op0(); - expr.op0().swap(tmp); + op0 = to_dereference_expr(op0).pointer(); } else { - assert(expr.op0().get_bool(ID_C_lvalue)); - expr.op0()=address_of_exprt(expr.op0()); + DATA_INVARIANT( + op0.get_bool(ID_C_lvalue), + "pointer-to-member must have lvalue operand"); + op0 = address_of_exprt(op0); } } - exprt tmp(expr.op1()); - tmp.type().set(ID_C_bound, expr.op0()); + exprt tmp(op1); + tmp.type().set(ID_C_bound, op0); expr.swap(tmp); return; } @@ -2279,14 +2284,13 @@ void cpp_typecheckt::explicit_typecast_ambiguity(exprt &expr) assert(expr.operands().size()==1); - irep_idt op0_id=expr.op0().id(); + irep_idt op0_id = to_unary_expr(expr).op().id(); - if(expr.type().id()==ID_cpp_name && - expr.op0().operands().size()==1 && - (op0_id==ID_unary_plus || - op0_id==ID_unary_minus || - op0_id==ID_address_of || - op0_id==ID_dereference)) + if( + expr.type().id() == ID_cpp_name && + to_unary_expr(expr).op().operands().size() == 1 && + (op0_id == ID_unary_plus || op0_id == ID_unary_minus || + op0_id == ID_address_of || op0_id == ID_dereference)) { exprt resolve_result= resolve( @@ -2301,8 +2305,10 @@ void cpp_typecheckt::explicit_typecast_ambiguity(exprt &expr) exprt new_binary_expr; new_binary_expr.operands().resize(2); - new_binary_expr.op0().swap(expr.type()); - new_binary_expr.op1().swap(expr.op0().op0()); + to_binary_expr(new_binary_expr).op0().swap(expr.type()); + to_binary_expr(new_binary_expr) + .op1() + .swap(to_unary_expr(to_unary_expr(expr).op()).op()); if(op0_id==ID_unary_plus) new_binary_expr.id(ID_plus); @@ -2313,7 +2319,8 @@ void cpp_typecheckt::explicit_typecast_ambiguity(exprt &expr) else if(op0_id==ID_dereference) new_binary_expr.id(ID_mult); - new_binary_expr.add_source_location()=expr.op0().source_location(); + new_binary_expr.add_source_location() = + to_unary_expr(expr).op().source_location(); expr.swap(new_binary_expr); } } @@ -2328,8 +2335,8 @@ void cpp_typecheckt::typecheck_expr_binary_arithmetic(exprt &expr) throw 0; } - add_implicit_dereference(expr.op0()); - add_implicit_dereference(expr.op1()); + add_implicit_dereference(to_binary_expr(expr).op0()); + add_implicit_dereference(to_binary_expr(expr).op1()); c_typecheck_baset::typecheck_expr_binary_arithmetic(expr); } @@ -2348,9 +2355,9 @@ void cpp_typecheckt::typecheck_expr_comma(exprt &expr) throw 0; } - if( - expr.op0().type().id() == ID_struct || - expr.op0().type().id() == ID_struct_tag) + const auto &op0_type = to_binary_expr(expr).op0().type(); + + if(op0_type.id() == ID_struct || op0_type.id() == ID_struct_tag) { // TODO: check if the comma operator has been overloaded! } diff --git a/src/cpp/cpp_typecheck_fargs.cpp b/src/cpp/cpp_typecheck_fargs.cpp index bec0d3c1ff8..fa66fcbac3c 100644 --- a/src/cpp/cpp_typecheck_fargs.cpp +++ b/src/cpp/cpp_typecheck_fargs.cpp @@ -34,7 +34,7 @@ void cpp_typecheck_fargst::build( const side_effect_expr_function_callt &function_call) { in_use=true; - operands = function_call.op1().operands(); + operands = function_call.arguments(); } bool cpp_typecheck_fargst::match( @@ -126,7 +126,7 @@ bool cpp_typecheck_fargst::match( operand.id() == ID_initializer_list && cpp_typecheck.cpp_is_pod(type) && operand.operands().size() == 1 && cpp_typecheck.implicit_conversion_sequence( - operand.op0(), type, new_expr, rank)) + to_unary_expr(operand).op(), type, new_expr, rank)) { distance += rank; } diff --git a/src/cpp/cpp_typecheck_function.cpp b/src/cpp/cpp_typecheck_function.cpp index 3ea088bb419..0a99473ea41 100644 --- a/src/cpp/cpp_typecheck_function.cpp +++ b/src/cpp/cpp_typecheck_function.cpp @@ -123,8 +123,10 @@ void cpp_typecheckt::convert_function(symbolt &symbol) PRECONDITION(symbol.value.get(ID_statement) == ID_block); if( - !symbol.value.has_operands() || !symbol.value.op0().has_operands() || - symbol.value.op0().op0().id() != ID_already_typechecked) + !symbol.value.has_operands() || + !to_multi_ary_expr(symbol.value).op0().has_operands() || + to_multi_ary_expr(to_multi_ary_expr(symbol.value).op0()).op0().id() != + ID_already_typechecked) { symbol.value.copy_to_operands( dtor(msymb, to_symbol_expr(function_scope.this_expr))); diff --git a/src/cpp/cpp_typecheck_initializer.cpp b/src/cpp/cpp_typecheck_initializer.cpp index 8ab4510a7ba..1b6c14aaa7c 100644 --- a/src/cpp/cpp_typecheck_initializer.cpp +++ b/src/cpp/cpp_typecheck_initializer.cpp @@ -74,10 +74,10 @@ void cpp_typecheckt::convert_initializer(symbolt &symbol) } else if(cpp_is_pod(symbol.type)) { - if(symbol.type.id() == ID_pointer && - symbol.type.subtype().id() == ID_code && - symbol.value.id() == ID_address_of && - symbol.value.op0().id() == ID_cpp_name) + if( + symbol.type.id() == ID_pointer && symbol.type.subtype().id() == ID_code && + symbol.value.id() == ID_address_of && + to_address_of_expr(symbol.value).object().id() == ID_cpp_name) { // initialization of a function pointer with // the address of a function: use pointer type information @@ -102,9 +102,11 @@ void cpp_typecheckt::convert_initializer(symbolt &symbol) fargs.operands.push_back(new_object); } - exprt resolved_expr=resolve( - to_cpp_name(static_cast(symbol.value.op0())), - cpp_typecheck_resolvet::wantt::BOTH, fargs); + exprt resolved_expr = resolve( + to_cpp_name( + static_cast(to_address_of_expr(symbol.value).object())), + cpp_typecheck_resolvet::wantt::BOTH, + fargs); assert(symbol.type.subtype() == resolved_expr.type()); @@ -119,7 +121,8 @@ void cpp_typecheckt::convert_initializer(symbolt &symbol) address_of_exprt( lookup(resolved_expr.get(ID_component_name)).symbol_expr()); - symbol.value.type().add(ID_to_member) = resolved_expr.op0().type(); + symbol.value.type().add(ID_to_member) = + to_member_expr(resolved_expr).compound().type(); } else UNREACHABLE; diff --git a/src/cpp/cpp_typecheck_resolve.cpp b/src/cpp/cpp_typecheck_resolve.cpp index 9b2dd7c7daf..35d742e355c 100644 --- a/src/cpp/cpp_typecheck_resolve.cpp +++ b/src/cpp/cpp_typecheck_resolve.cpp @@ -2154,7 +2154,7 @@ bool cpp_typecheck_resolvet::disambiguate_functions( } cpp_typecheck_fargst new_fargs(fargs); - new_fargs.add_object(expr.op0()); + new_fargs.add_object(to_member_expr(expr).compound()); return new_fargs.match(type, args_distance, cpp_typecheck); } diff --git a/src/cpp/expr2cpp.cpp b/src/cpp/expr2cpp.cpp index cba5bb227f8..2d884567e33 100644 --- a/src/cpp/expr2cpp.cpp +++ b/src/cpp/expr2cpp.cpp @@ -404,7 +404,7 @@ std::string expr2cppt::convert_code_cpp_delete( return convert_norep(src, precedence); } - std::string tmp=convert(src.op0()); + std::string tmp = convert(to_unary_expr(src).op()); dest+=tmp+";\n"; @@ -476,16 +476,17 @@ std::string expr2cppt::convert_code( std::string expr2cppt::convert_extractbit(const exprt &src) { - assert(src.operands().size()==2); - return convert(src.op0())+"["+convert(src.op1())+"]"; + const auto &extractbit_expr = to_extractbit_expr(src); + return convert(extractbit_expr.op0()) + "[" + convert(extractbit_expr.op1()) + + "]"; } std::string expr2cppt::convert_extractbits(const exprt &src) { - assert(src.operands().size()==3); - return - convert(src.op0())+".range("+convert(src.op1())+ ","+ - convert(src.op2())+")"; + const auto &extractbits_expr = to_extractbits_expr(src); + return convert(extractbits_expr.src()) + ".range(" + + convert(extractbits_expr.upper()) + "," + + convert(extractbits_expr.lower()) + ")"; } std::string expr2cpp(const exprt &expr, const namespacet &ns)