diff --git a/regression/goto-analyzer/precise-const-fp-supurious-const-loss/main.c b/regression/goto-analyzer/precise-const-fp-supurious-const-loss/main.c new file mode 100644 index 00000000000..4041b2f6aa1 --- /dev/null +++ b/regression/goto-analyzer/precise-const-fp-supurious-const-loss/main.c @@ -0,0 +1,41 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +const int const_number=4; + +void func() +{ + // Here we 'lose' const-ness except it is a copy so we shouldn't care + int non_const_number=const_number; + const void_fp fp = f2; + + + // Here also we lose const-ness except it is a copy of pointer so we + // shouldn't care + const void_fp * const p2fp = &f2; + const void_fp * p2fp_non_const = &p2fp; + + fp(); +} + +int main() +{ + func(); + + return 0; +} diff --git a/regression/goto-analyzer/precise-const-fp-supurious-const-loss/test.desc b/regression/goto-analyzer/precise-const-fp-supurious-const-loss/test.desc new file mode 100644 index 00000000000..76734999981 --- /dev/null +++ b/regression/goto-analyzer/precise-const-fp-supurious-const-loss/test.desc @@ -0,0 +1,18 @@ +CORE +main.c +--show-goto-functions --verbosity 10 --pointer-check +^Removing function pointers and virtual functions$ +^\s*f2\(\); +-- +^warning: ignoring +^\s*\d+:\s*f1\(\); +^\s*\d+:\s*f3\(\); +^\s*\d+:\s*f4\(\); +^\s*\d+:\s*f5\(\); +^\s*\d+:\s*f6\(\); +^\s*\d+:\s*f7\(\); +^\s*\d+:\s*f8\(\); +^\s*\d+:\s*f9\(\); +-- +Though this example program appears to lose const-ness, since it is a primitive +it is a copy so it is irrelevant. diff --git a/src/analyses/does_remove_const.cpp b/src/analyses/does_remove_const.cpp index 90d82f99e19..1afe39f231c 100644 --- a/src/analyses/does_remove_const.cpp +++ b/src/analyses/does_remove_const.cpp @@ -47,7 +47,7 @@ bool does_remove_constt::operator()() const // Compare the types recursively for a point where the rhs is more // const that the lhs - if(!is_type_at_least_as_const_as(&lhs_type, &rhs_type)) + if(!does_type_preserve_const_correctness(&lhs_type, &rhs_type)) { return true; } @@ -78,7 +78,7 @@ bool does_remove_constt::does_expr_lose_const(const exprt &expr) const if(base_type_eq(op_type, root_type, ns)) { // Is this child more const-qualified than the root - if(!is_type_at_least_as_const_as(&root_type, &op_type)) + if(!does_type_preserve_const_correctness(&root_type, &op_type)) { return true; } @@ -93,37 +93,78 @@ bool does_remove_constt::does_expr_lose_const(const exprt &expr) const return false; } -/// A recursive check to check the type_more_const is at least as const as type -/// compare. +/// A recursive check that handles when assigning a source value to a target, is +/// the assignment a loss of const-correctness. /// -/// type_more_const | type_compare || result -/// ---------------------------------------- -/// const int * | const int * -> true -/// int * | const int * -> false -/// const int * | int * -> true -/// int * | int * const -> false +/// For primitive types, it always returns true since these are copied +/// +/// For pointers we requires that if in the source it's value couldn't +/// be modified, then it still can't be modified in the target +/// +/// target_type | source_type || result +/// ---------------------------------------- +/// const int | int -> true +/// int | const int -> true +/// const int | const int -> true +/// int | int -> true +/// +/// int * | int * const -> true +/// int * | const int * -> false +/// const int * | int * -> true +/// const int * | const int * -> true +/// int * const | int * -> true +/// +/// See unit/analyses/does_type_preserve_const_correcness for +/// comprehensive list +/// \param target_type: the resulting type +/// \param source_type: the starting type +/// \return Returns true if a value of type source_type could be assigned into a +/// a value of target_type without losing const-correctness +bool does_remove_constt::does_type_preserve_const_correctness( + const typet *target_type, const typet *source_type) const +{ + while(target_type->id()==ID_pointer) + { + bool direct_subtypes_at_least_as_const= + is_type_at_least_as_const_as( + target_type->subtype(), source_type->subtype()); + // We have a pointer to something, but the thing it is pointing to can't be + // modified normally, but can through this pointer + if(!direct_subtypes_at_least_as_const) + return false; + // Check the subtypes if they are pointers + target_type=&target_type->subtype(); + source_type=&source_type->subtype(); + } + return true; +} + +/// A simple check to check the type_more_const is at least as const as type +/// compare. This only checks the exact type, use +/// `is_pointer_at_least_as_constant_as` for dealing with nested types +/// +/// type_more_const | type_compare || result +/// ---------------------------------------- +/// const int | int -> true +/// int | const int -> false +/// const int | const int -> true +/// int | int -> true +/// int * | int * const -> false +/// int * | const int * -> true +/// const int * | int * -> true +/// int * const | int * -> true +/// +/// See unit/analyses/is_type_as_least_as_const_as for comprehensive list /// \param type_more_const: the type we are expecting to be at least as const /// qualified /// \param type_compare: the type we are comparing against which may be less /// const qualified /// \return Returns true if type_more_const is at least as const as type_compare bool does_remove_constt::is_type_at_least_as_const_as( - const typet *type_more_const, const typet *type_compare) const + const typet &type_more_const, const typet &type_compare) const { - while(type_compare->id()!=ID_nil && type_more_const->id()!=ID_nil) - { - const c_qualifierst rhs_qualifiers(*type_compare); - const c_qualifierst lhs_qualifiers(*type_more_const); - if(rhs_qualifiers.is_constant && !lhs_qualifiers.is_constant) - { - return false; - } - - type_compare=&type_compare->subtype(); - type_more_const=&type_more_const->subtype(); - } - - // Both the types should have the same number of subtypes - assert(type_compare->id()==ID_nil && type_more_const->id()==ID_nil); - return true; + const c_qualifierst type_compare_qualifiers(type_compare); + const c_qualifierst more_constant_qualifiers(type_more_const); + return !type_compare_qualifiers.is_constant || + more_constant_qualifiers.is_constant; } diff --git a/src/analyses/does_remove_const.h b/src/analyses/does_remove_const.h index f0cf2a25799..a15ec0f7711 100644 --- a/src/analyses/does_remove_const.h +++ b/src/analyses/does_remove_const.h @@ -12,6 +12,7 @@ #define CPROVER_ANALYSES_DOES_REMOVE_CONST_H #include +#include class goto_programt; @@ -25,10 +26,15 @@ class does_remove_constt bool does_expr_lose_const(const exprt &expr) const; bool is_type_at_least_as_const_as( - const typet *type_more_const, const typet *type_compare) const; + const typet &type_more_const, const typet &type_compare) const; + + bool does_type_preserve_const_correctness( + const typet *target_type, const typet *source_type) const; const goto_programt &goto_program; const namespacet &ns; + + friend class does_remove_const_testt; }; #endif // CPROVER_ANALYSES_DOES_REMOVE_CONST_H diff --git a/unit/Makefile b/unit/Makefile index a1de1539ee7..0afe7916788 100644 --- a/unit/Makefile +++ b/unit/Makefile @@ -1,6 +1,9 @@ .PHONY: all cprover.dir test SRC = unit_tests.cpp \ + analyses/does_remove_const/does_expr_lose_const.cpp \ + analyses/does_remove_const/does_type_preserve_const_correctness.cpp \ + analyses/does_remove_const/is_type_at_least_as_const_as.cpp \ catch_example.cpp \ # Empty last line diff --git a/unit/analyses/does_remove_const/does_expr_lose_const.cpp b/unit/analyses/does_remove_const/does_expr_lose_const.cpp new file mode 100644 index 00000000000..80e223c93be --- /dev/null +++ b/unit/analyses/does_remove_const/does_expr_lose_const.cpp @@ -0,0 +1,376 @@ +/*******************************************************************\ + + Module: Does Remove Const Unit Tests + + Author: DiffBlue Limited. All rights reserved. + +\*******************************************************************/ + +/// \file +/// Does Remove Const Unit Tests + +#include +#include +#include +#include +#include +#include +#include +#include + + +SCENARIO("does_expr_lose_const", + "[core][analyses][does_remove_const][does_expr_remove_const]") +{ + symbol_tablet symbol_table; + namespacet ns(symbol_table); + goto_programt program; + does_remove_constt does_remove_const(program, ns); + does_remove_const_testt does_remove_const_test(does_remove_const); + + GIVEN("Const and non-const primitive and pointers to primitives") + { + c_qualifierst const_qualifier; + const_qualifier.is_constant=true; + + // const int + typet const_primitive_type=integer_typet(); + const_qualifier.write(const_primitive_type); + + // int + typet non_const_primitive_type=integer_typet(); + + // pointer (can be reassigned) + // to int (value can be changed) + // int * + typet pointer_to_int_type=pointer_typet(non_const_primitive_type); + + // const pointer (can't be reassigned) + // to int (value can be changed) + // int * const + typet const_pointer_to_int_type=pointer_typet(non_const_primitive_type); + const_qualifier.write(const_pointer_to_int_type); + + // pointer (can be reassigned) + // to const int (value can't be changed) + // const int * + typet pointer_to_const_int_type=pointer_typet(const_primitive_type); + + // constant pointer (can't be reassigned) + // to const int (value can't be changed) + // const int * const + typet const_pointer_to_const_int_type=pointer_typet(const_primitive_type); + const_qualifier.write(const_pointer_to_const_int_type); + + symbol_exprt const_primitive_symbol( + "const_primitive", const_primitive_type); + symbol_exprt non_const_primitive_symbol( + "non_const_primitive", non_const_primitive_type); + symbol_exprt pointer_to_int_symbol( + "pointer_to_int", pointer_to_int_type); + symbol_exprt const_pointer_to_int_symbol( + "const_pointer_to_int", const_pointer_to_int_type); + symbol_exprt pointer_to_const_int_symbol( + "pointer_to_const_int", pointer_to_const_int_type); + symbol_exprt const_pointer_to_const_int_symbol( + "const_pointer_to_const_int", const_pointer_to_const_int_type); + + WHEN("Casting from int to int") + { + typecast_exprt cast_expr( + non_const_primitive_symbol, non_const_primitive_type); + + THEN("The cast_expr does not lose const-correctness") + { + bool result=does_remove_const_test.does_expr_lose_const(cast_expr); + REQUIRE_FALSE(result); + } + } + WHEN("Casting from const int to int") + { + typecast_exprt cast_expr( + non_const_primitive_symbol, const_primitive_type); + + THEN("The cast_expr does not lose const-correctness") + { + bool result=does_remove_const_test.does_expr_lose_const(cast_expr); + REQUIRE_FALSE(result); + } + } + WHEN("Casting from int to const int") + { + typecast_exprt cast_expr( + non_const_primitive_symbol, const_primitive_type); + + THEN("The cast_expr does not lose const-correctness") + { + bool result=does_remove_const_test.does_expr_lose_const(cast_expr); + REQUIRE_FALSE(result); + } + } + WHEN("Casting from const int to const int") + { + typecast_exprt cast_expr( + const_primitive_symbol, const_primitive_type); + + THEN("The cast_expr does not lose const-correctness") + { + bool result=does_remove_const_test.does_expr_lose_const(cast_expr); + REQUIRE_FALSE(result); + } + } + WHEN("Casting from int * to int *") + { + typecast_exprt cast_expr( + pointer_to_int_symbol, pointer_to_int_type); + THEN("The cast_expr does not lose const-correctness") + { + bool result=does_remove_const_test.does_expr_lose_const(cast_expr); + REQUIRE_FALSE(result); + } + } + WHEN("Casting from const int * to int *") + { + typecast_exprt cast_expr( + pointer_to_const_int_symbol, pointer_to_int_type); + THEN("The cast_expr does lose const-correctness") + { + bool result=does_remove_const_test.does_expr_lose_const(cast_expr); + REQUIRE(result); + } + } + WHEN("Casting from int * b const to int *") + { + typecast_exprt cast_expr( + const_pointer_to_int_symbol, pointer_to_int_type); + THEN("The cast_expr does not lose const-correctness") + { + bool result=does_remove_const_test.does_expr_lose_const(cast_expr); + REQUIRE_FALSE(result); + } + } + WHEN("Casting from const int * b const to int *") + { + typecast_exprt cast_expr( + const_pointer_to_const_int_symbol, pointer_to_int_type); + THEN("The cast_expr does lose const-correctness") + { + bool result=does_remove_const_test.does_expr_lose_const(cast_expr); + REQUIRE(result); + } + } + WHEN("Casting from int * to const int *") + { + typecast_exprt cast_expr( + pointer_to_int_symbol, pointer_to_const_int_type); + THEN("The cast_expr does not lose const-correctness") + { + bool result=does_remove_const_test.does_expr_lose_const(cast_expr); + REQUIRE_FALSE(result); + } + } + WHEN("Casting from const int * to const int *") + { + typecast_exprt cast_expr( + pointer_to_const_int_symbol, pointer_to_const_int_type); + THEN("The cast_expr does not lose const-correctness") + { + bool result=does_remove_const_test.does_expr_lose_const(cast_expr); + REQUIRE_FALSE(result); + } + } + WHEN("Casting from int * b const to const int *") + { + typecast_exprt cast_expr( + const_pointer_to_int_symbol, pointer_to_const_int_type); + THEN("The cast_expr does not lose const-correctness") + { + bool result=does_remove_const_test.does_expr_lose_const(cast_expr); + REQUIRE_FALSE(result); + } + } + WHEN("Casting from const int * b const to const int *") + { + typecast_exprt cast_expr( + const_pointer_to_const_int_symbol, pointer_to_const_int_type); + THEN("The cast_expr does not lose const-correctness") + { + bool result=does_remove_const_test.does_expr_lose_const(cast_expr); + REQUIRE_FALSE(result); + } + } + WHEN("Casting from int * to int * const") + { + typecast_exprt cast_expr( + pointer_to_int_symbol, const_pointer_to_int_type); + THEN("The cast_expr does not lose const-correctness") + { + bool result=does_remove_const_test.does_expr_lose_const(cast_expr); + REQUIRE_FALSE(result); + } + } + WHEN("Casting from const int * to int * const") + { + typecast_exprt cast_expr( + pointer_to_const_int_symbol, const_pointer_to_int_type); + THEN("The cast_expr does lose const-correctness") + { + bool result=does_remove_const_test.does_expr_lose_const(cast_expr); + REQUIRE(result); + } + } + WHEN("Casting from int * b const to int * const") + { + typecast_exprt cast_expr( + const_pointer_to_int_symbol, const_pointer_to_int_type); + THEN("The cast_expr does not lose const-correctness") + { + bool result=does_remove_const_test.does_expr_lose_const(cast_expr); + REQUIRE_FALSE(result); + } + } + WHEN("Casting from const int * b const to int * const") + { + typecast_exprt cast_expr( + const_pointer_to_const_int_symbol, const_pointer_to_int_type); + THEN("The cast_expr does not lose const-correctness") + { + bool result=does_remove_const_test.does_expr_lose_const(cast_expr); + REQUIRE(result); + } + } + WHEN("Casting from int * to const int * const") + { + typecast_exprt cast_expr( + pointer_to_int_symbol, const_pointer_to_const_int_type); + THEN("The cast_expr does not lose const-correctness") + { + bool result=does_remove_const_test.does_expr_lose_const(cast_expr); + REQUIRE_FALSE(result); + } + } + WHEN("Casting from const int * to const int * const") + { + typecast_exprt cast_expr( + pointer_to_const_int_symbol, const_pointer_to_const_int_type); + THEN("The cast_expr does not lose const-correctness") + { + bool result=does_remove_const_test.does_expr_lose_const(cast_expr); + REQUIRE_FALSE(result); + } + } + WHEN("Casting from int * b const to const int * const") + { + typecast_exprt cast_expr( + const_pointer_to_int_symbol, const_pointer_to_const_int_type); + THEN("The cast_expr does not lose const-correctness") + { + bool result=does_remove_const_test.does_expr_lose_const(cast_expr); + REQUIRE_FALSE(result); + } + } + WHEN("Casting from const int * b const to const int * const") + { + typecast_exprt cast_expr( + const_pointer_to_const_int_symbol, const_pointer_to_const_int_type); + THEN("The cast_expr does not lose const-correctness") + { + bool result=does_remove_const_test.does_expr_lose_const(cast_expr); + REQUIRE_FALSE(result); + } + } + + WHEN("Casting from &(int) to int *") + { + typecast_exprt cast_expr( + address_of_exprt(non_const_primitive_symbol), pointer_to_int_type); + + THEN("The typecast_expr does not lose const-correctness") + { + bool result=does_remove_const_test.does_expr_lose_const(cast_expr); + REQUIRE_FALSE(result); + } + } + WHEN("Casting from &(const int) to int *") + { + typecast_exprt cast_expr( + address_of_exprt(const_primitive_symbol), pointer_to_int_type); + + THEN("The cast_expr does lose const-correctness") + { + bool result=does_remove_const_test.does_expr_lose_const(cast_expr); + REQUIRE(result); + } + } + WHEN("Casting from &(int) to const int *") + { + typecast_exprt cast_expr( + address_of_exprt(non_const_primitive_symbol), + pointer_to_const_int_type); + + THEN("The cast_expr does not lose const-correctness") + { + bool result=does_remove_const_test.does_expr_lose_const(cast_expr); + REQUIRE_FALSE(result); + } + } + WHEN("Casting from &(const int) to const int *") + { + typecast_exprt cast_expr( + address_of_exprt(const_primitive_symbol), pointer_to_const_int_type); + + THEN("The cast_expr does not lose const-correctness") + { + bool result=does_remove_const_test.does_expr_lose_const(cast_expr); + REQUIRE_FALSE(result); + } + } + WHEN("Casting from &(int) to int * const") + { + typecast_exprt cast_expr( + address_of_exprt(non_const_primitive_symbol), + const_pointer_to_int_type); + + THEN("The cast_expr does not lose const-correctness") + { + bool result=does_remove_const_test.does_expr_lose_const(cast_expr); + REQUIRE_FALSE(result); + } + } + WHEN("Casting from &(const int) to int * const") + { + typecast_exprt cast_expr( + address_of_exprt(const_primitive_symbol), const_pointer_to_int_type); + + THEN("The cast_expr does lose const-correctness") + { + bool result=does_remove_const_test.does_expr_lose_const(cast_expr); + REQUIRE(result); + } + } + WHEN("Casting from &(int) to const int * const") + { + typecast_exprt cast_expr( + address_of_exprt(non_const_primitive_symbol), + const_pointer_to_const_int_type); + + THEN("The cast_expr does not lose const-correctness") + { + bool result=does_remove_const_test.does_expr_lose_const(cast_expr); + REQUIRE_FALSE(result); + } + } + WHEN("Casting from &(const int) to const int * const") + { + typecast_exprt cast_expr( + address_of_exprt(const_primitive_symbol), + const_pointer_to_const_int_type); + + THEN("The cast_expr does not lose const-correctness") + { + bool result=does_remove_const_test.does_expr_lose_const(cast_expr); + REQUIRE_FALSE(result); + } + } + } +} diff --git a/unit/analyses/does_remove_const/does_remove_const_util.h b/unit/analyses/does_remove_const/does_remove_const_util.h new file mode 100644 index 00000000000..e1a459b6c1b --- /dev/null +++ b/unit/analyses/does_remove_const/does_remove_const_util.h @@ -0,0 +1,49 @@ +/*******************************************************************\ + + Module: Does Remove Const Unit Tests + + Author: DiffBlue Limited. All rights reserved. + +\*******************************************************************/ + +/// \file +/// Does Remove Const Unit Tests + +#ifndef CPROVER__ANALYSES_DOES_REMOVE_CONST_DOES_REMOVE_CONST_UTIL_H +#define CPROVER__ANALYSES_DOES_REMOVE_CONST_DOES_REMOVE_CONST_UTIL_H + +#include + +// This class provides access to private members and functions of +// does_remove_const +class does_remove_const_testt +{ +public: + explicit does_remove_const_testt(does_remove_constt does_remove_const): + does_remove_const(does_remove_const) + {} + + bool does_expr_lose_const(const exprt &expr) const + { + return does_remove_const.does_expr_lose_const(expr); + } + + bool is_type_at_least_as_const_as( + const typet &type_more_const, const typet &type_compare) const + { + return does_remove_const.is_type_at_least_as_const_as( + type_more_const, type_compare); + } + + bool does_type_preserve_const_correctness( + const typet *target_type, const typet *source_type) const + { + return does_remove_const.does_type_preserve_const_correctness( + target_type, source_type); + } + +private: + does_remove_constt does_remove_const; +}; + +#endif // CPROVER__ANALYSES_DOES_REMOVE_CONST_DOES_REMOVE_CONST_UTIL_H diff --git a/unit/analyses/does_remove_const/does_type_preserve_const_correctness.cpp b/unit/analyses/does_remove_const/does_type_preserve_const_correctness.cpp new file mode 100644 index 00000000000..0f10081c49b --- /dev/null +++ b/unit/analyses/does_remove_const/does_type_preserve_const_correctness.cpp @@ -0,0 +1,265 @@ +/*******************************************************************\ + + Module: Does Remove Const Unit Tests + + Author: DiffBlue Limited. All rights reserved. + +\*******************************************************************/ + +/// \file +/// Does Remove Const Unit Tests + +#include + +#include +#include +#include +#include +#include +#include + +SCENARIO("does_type_preserve_const_correctness", + "[core][analyses][does_remove_const][does_type_preserve_const_correctness]") +{ + symbol_tablet symbol_table; + namespacet ns(symbol_table); + goto_programt program; + does_remove_constt does_remove_const(program, ns); + does_remove_const_testt does_remove_const_test(does_remove_const); + + GIVEN("Const and non-const primitive and pointers to primitives") + { + c_qualifierst const_qualifier; + const_qualifier.is_constant=true; + + // const int + typet const_primitive_type=integer_typet(); + const_qualifier.write(const_primitive_type); + + // int + typet non_const_primitive_type=integer_typet(); + + // pointer (can be reassigned) + // to int (value can be changed) + // int * + typet pointer_to_int_type=pointer_typet(non_const_primitive_type); + + // const pointer (can't be reassigned) + // to int (value can be changed) + // int * const + typet const_pointer_to_int_type=pointer_typet(non_const_primitive_type); + const_qualifier.write(const_pointer_to_int_type); + + // pointer (can be reassigned) + // to const int (value can't be changed) + // const int * + typet pointer_to_const_int_type=pointer_typet(const_primitive_type); + + // constant pointer (can't be reassigned) + // to const int (value can't be changed) + // const int * const + typet const_pointer_to_const_int_type=pointer_typet(const_primitive_type); + const_qualifier.write(const_pointer_to_const_int_type); + + WHEN("Comparing int to int") + { + THEN("The target type preserves the const-correctness of the source type") + { + bool result= + does_remove_const_test.does_type_preserve_const_correctness( + &non_const_primitive_type, &non_const_primitive_type); + REQUIRE(result); + } + } + WHEN("Comparing const int to int") + { + THEN("The target type preserves the const-correctness of the source type") + { + bool result= + does_remove_const_test.does_type_preserve_const_correctness( + &const_primitive_type, &non_const_primitive_type); + REQUIRE(result); + } + } + WHEN("Comparing int to const int") + { + THEN("The target type preserves the const-correctness of the source type") + { + bool result= + does_remove_const_test.does_type_preserve_const_correctness( + &non_const_primitive_type, &const_primitive_type); + REQUIRE(result); + } + } + WHEN("Comparing const int to const int") + { + THEN("The target type preserves the const-correctness of the source type") + { + bool result= + does_remove_const_test.does_type_preserve_const_correctness( + &const_primitive_type, &const_primitive_type); + REQUIRE(result); + } + } + WHEN("Comparing int * to int *") + { + THEN("The target type preserves the const-correctness of the source type") + { + bool result= + does_remove_const_test.does_type_preserve_const_correctness( + &pointer_to_int_type, &pointer_to_int_type); + REQUIRE(result); + } + } + WHEN("Comparing const int * to int *") + { + THEN("The target type preserves the const-correctness of the source type") + { + bool result= + does_remove_const_test.does_type_preserve_const_correctness( + &pointer_to_const_int_type, &pointer_to_int_type); + REQUIRE(result); + } + } + WHEN("Comparing int * b const to int *") + { + THEN("The target type preserves the const-correctness of the source type") + { + bool result= + does_remove_const_test.does_type_preserve_const_correctness( + &const_pointer_to_int_type, &pointer_to_int_type); + REQUIRE(result); + } + } + WHEN("Comparing const int * b const to int *") + { + THEN("The target type preserves the const-correctness of the source type") + { + bool result= + does_remove_const_test.does_type_preserve_const_correctness( + &const_pointer_to_const_int_type, &pointer_to_int_type); + REQUIRE(result); + } + } + WHEN("Comparing int * to const int *") + { + THEN("The target type loses const-correctness of the source type") + { + bool result= + does_remove_const_test.does_type_preserve_const_correctness( + &pointer_to_int_type, &pointer_to_const_int_type); + REQUIRE_FALSE(result); + } + } + WHEN("Comparing const int * to const int *") + { + THEN("The target type preserves the const-correctness of the source type") + { + bool result= + does_remove_const_test.does_type_preserve_const_correctness( + &pointer_to_const_int_type, &pointer_to_const_int_type); + REQUIRE(result); + } + } + WHEN("Comparing int * b const to const int *") + { + THEN("The target type loses const-correctness of the source type") + { + bool result= + does_remove_const_test.does_type_preserve_const_correctness( + &const_pointer_to_int_type, &pointer_to_const_int_type); + REQUIRE_FALSE(result); + } + } + WHEN("Comparing const int * b const to const int *") + { + THEN("The target type preserves the const-correctness of the source type") + { + bool result= + does_remove_const_test.does_type_preserve_const_correctness( + &const_pointer_to_const_int_type, &pointer_to_const_int_type); + REQUIRE(result); + } + } + WHEN("Comparing int * to int * const") + { + THEN("The target type preserves the const-correctness of the source type") + { + bool result= + does_remove_const_test.does_type_preserve_const_correctness( + &pointer_to_int_type, &const_pointer_to_int_type); + REQUIRE(result); + } + } + WHEN("Comparing const int * to int * const") + { + THEN("The target type preserves the const-correctness of the source type") + { + bool result= + does_remove_const_test.does_type_preserve_const_correctness( + &pointer_to_const_int_type, &const_pointer_to_int_type); + REQUIRE(result); + } + } + WHEN("Comparing int * b const to int * const") + { + THEN("The target type preserves the const-correctness of the source type") + { + bool result= + does_remove_const_test.does_type_preserve_const_correctness( + &const_pointer_to_int_type, &const_pointer_to_int_type); + REQUIRE(result); + } + } + WHEN("Comparing const int * b const to int * const") + { + THEN("The target type preserves the const-correctness of the source type") + { + bool result= + does_remove_const_test.does_type_preserve_const_correctness( + &const_pointer_to_const_int_type, &const_pointer_to_int_type); + REQUIRE(result); + } + } + WHEN("Comparing int * to const int * const") + { + THEN("The target type loses const-correctness of the source type") + { + bool result= + does_remove_const_test.does_type_preserve_const_correctness( + &pointer_to_int_type, &const_pointer_to_const_int_type); + REQUIRE_FALSE(result); + } + } + WHEN("Comparing const int * to const int * const") + { + THEN("The target type preserves the const-correctness of the source type") + { + bool result= + does_remove_const_test.does_type_preserve_const_correctness( + &pointer_to_const_int_type, &const_pointer_to_const_int_type); + REQUIRE(result); + } + } + WHEN("Comparing int * b const to const int * const") + { + THEN("The target type loses const-correctness of the source type") + { + bool result= + does_remove_const_test.does_type_preserve_const_correctness( + &const_pointer_to_int_type, &const_pointer_to_const_int_type); + REQUIRE_FALSE(result); + } + } + WHEN("Comparing const int * b const to const int * const") + { + THEN("The target type preserves the const-correctness of the source type") + { + bool result= + does_remove_const_test.does_type_preserve_const_correctness( + &const_pointer_to_const_int_type, &const_pointer_to_const_int_type); + REQUIRE(result); + } + } + } +} diff --git a/unit/analyses/does_remove_const/is_type_at_least_as_const_as.cpp b/unit/analyses/does_remove_const/is_type_at_least_as_const_as.cpp new file mode 100644 index 00000000000..cfb2c647536 --- /dev/null +++ b/unit/analyses/does_remove_const/is_type_at_least_as_const_as.cpp @@ -0,0 +1,265 @@ +/*******************************************************************\ + + Module: Does Remove Const Unit Tests + + Author: DiffBlue Limited. All rights reserved. + +\*******************************************************************/ + +/// \file +/// Does Remove Const Unit Tests + +#include + +#include +#include +#include +#include +#include +#include + +SCENARIO("is_type_at_least_as_const", + "[core][analyses][does_remove_const][is_type_at_least_as_const]") +{ + symbol_tablet symbol_table; + namespacet ns(symbol_table); + goto_programt program; + does_remove_constt does_remove_const(program, ns); + does_remove_const_testt does_remove_const_test(does_remove_const); + + GIVEN("Const and non-const primitive and pointers to primitives") + { + c_qualifierst const_qualifier; + const_qualifier.is_constant=true; + + // const int + typet const_primitive_type=integer_typet(); + const_qualifier.write(const_primitive_type); + + // int + typet non_const_primitive_type=integer_typet(); + + // pointer (can be reassigned) + // to int (value can be changed) + // int * + typet pointer_to_int_type=pointer_typet(non_const_primitive_type); + + // const pointer (can't be reassigned) + // to int (value can be changed) + // int * const + typet const_pointer_to_int_type=pointer_typet(non_const_primitive_type); + const_qualifier.write(const_pointer_to_int_type); + + // pointer (can be reassigned) + // to const int (value can't be changed) + // const int * + typet pointer_to_const_int_type=pointer_typet(const_primitive_type); + + // constant pointer (can't be reassigned) + // to const int (value can't be changed) + // const int * const + typet const_pointer_to_const_int_type=pointer_typet(const_primitive_type); + const_qualifier.write(const_pointer_to_const_int_type); + + WHEN("Comparing int to int") + { + THEN("The first type is at least as const as the second type") + { + bool result= + does_remove_const_test.is_type_at_least_as_const_as( + non_const_primitive_type, non_const_primitive_type); + REQUIRE(result); + } + } + WHEN("Comparing const int to int") + { + THEN("The first type is at least as const as the second type") + { + bool result= + does_remove_const_test.is_type_at_least_as_const_as( + const_primitive_type, non_const_primitive_type); + REQUIRE(result); + } + } + WHEN("Comparing int to const int") + { + THEN("The first type is less const than the second type") + { + bool result= + does_remove_const_test.is_type_at_least_as_const_as( + non_const_primitive_type, const_primitive_type); + REQUIRE_FALSE(result); + } + } + WHEN("Comparing const int to const int") + { + THEN("The first type is at least as const as the second type") + { + bool result= + does_remove_const_test.is_type_at_least_as_const_as( + const_primitive_type, const_primitive_type); + REQUIRE(result); + } + } + WHEN("Comparing int * to int *") + { + THEN("The first type is at least as const as the second type") + { + bool result= + does_remove_const_test.is_type_at_least_as_const_as( + pointer_to_int_type, pointer_to_int_type); + REQUIRE(result); + } + } + WHEN("Comparing const int * to int *") + { + THEN("The first type is at least as const as the second type") + { + bool result= + does_remove_const_test.is_type_at_least_as_const_as( + pointer_to_const_int_type, pointer_to_int_type); + REQUIRE(result); + } + } + WHEN("Comparing int * b const to int *") + { + THEN("The first type is at least as const as the second type") + { + bool result= + does_remove_const_test.is_type_at_least_as_const_as( + const_pointer_to_int_type, pointer_to_int_type); + REQUIRE(result); + } + } + WHEN("Comparing const int * b const to int *") + { + THEN("The first type is at least as const as the second type") + { + bool result= + does_remove_const_test.is_type_at_least_as_const_as( + const_pointer_to_const_int_type, pointer_to_int_type); + REQUIRE(result); + } + } + WHEN("Comparing int * to const int *") + { + THEN("The first type is at least as const as the second type") + { + bool result= + does_remove_const_test.is_type_at_least_as_const_as( + pointer_to_int_type, pointer_to_const_int_type); + REQUIRE(result); + } + } + WHEN("Comparing const int * to const int *") + { + THEN("The first type is at least as const as the second type") + { + bool result= + does_remove_const_test.is_type_at_least_as_const_as( + pointer_to_const_int_type, pointer_to_const_int_type); + REQUIRE(result); + } + } + WHEN("Comparing int * b const to const int *") + { + THEN("The first type is at least as const as the second type") + { + bool result= + does_remove_const_test.is_type_at_least_as_const_as( + const_pointer_to_int_type, pointer_to_const_int_type); + REQUIRE(result); + } + } + WHEN("Comparing const int * b const to const int *") + { + THEN("The first type is at least as const as the second type") + { + bool result= + does_remove_const_test.is_type_at_least_as_const_as( + const_pointer_to_const_int_type, pointer_to_const_int_type); + REQUIRE(result); + } + } + WHEN("Comparing int * to int * const") + { + THEN("The first type is less const as the second type") + { + bool result= + does_remove_const_test.is_type_at_least_as_const_as( + pointer_to_int_type, const_pointer_to_int_type); + REQUIRE_FALSE(result); + } + } + WHEN("Comparing const int * to int * const") + { + THEN("The first type is less const as the second type") + { + bool result= + does_remove_const_test.is_type_at_least_as_const_as( + pointer_to_const_int_type, const_pointer_to_int_type); + REQUIRE_FALSE(result); + } + } + WHEN("Comparing int * b const to int * const") + { + THEN("The first type is at least as const as the second type") + { + bool result= + does_remove_const_test.is_type_at_least_as_const_as( + const_pointer_to_int_type, const_pointer_to_int_type); + REQUIRE(result); + } + } + WHEN("Comparing const int * b const to int * const") + { + THEN("The first type is at least as const as the second type") + { + bool result= + does_remove_const_test.is_type_at_least_as_const_as( + const_pointer_to_const_int_type, const_pointer_to_int_type); + REQUIRE(result); + } + } + WHEN("Comparing int * to const int * const") + { + THEN("The first type is less const than the second type") + { + bool result= + does_remove_const_test.is_type_at_least_as_const_as( + pointer_to_int_type, const_pointer_to_const_int_type); + REQUIRE_FALSE(result); + } + } + WHEN("Comparing const int * to const int * const") + { + THEN("The first type is less const than the second type") + { + bool result= + does_remove_const_test.is_type_at_least_as_const_as( + pointer_to_const_int_type, const_pointer_to_const_int_type); + REQUIRE_FALSE(result); + } + } + WHEN("Comparing int * b const to const int * const") + { + THEN("The first type is at least as const as the second type") + { + bool result= + does_remove_const_test.is_type_at_least_as_const_as( + const_pointer_to_int_type, const_pointer_to_const_int_type); + REQUIRE(result); + } + } + WHEN("Comparing const int * b const to const int * const") + { + THEN("The first type is at least as const as the second type") + { + bool result= + does_remove_const_test.is_type_at_least_as_const_as( + const_pointer_to_const_int_type, const_pointer_to_const_int_type); + REQUIRE(result); + } + } + } +}