Skip to content

Commit 3e9b76d

Browse files
author
svorenova
authored
Merge pull request #2815 from svorenova/cleanup_typet
Cleanup types [DOC-12]
2 parents b656cc9 + 1a28613 commit 3e9b76d

11 files changed

+590
-346
lines changed

jbmc/src/java_bytecode/ci_lazy_methods_needed.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,11 @@ Author: Chris Smowton, [email protected]
1212
#ifndef CPROVER_JAVA_BYTECODE_CI_LAZY_METHODS_H
1313
#define CPROVER_JAVA_BYTECODE_CI_LAZY_METHODS_H
1414

15-
#include <vector>
1615
#include <set>
1716
#include <unordered_set>
17+
#include <util/namespace.h>
1818
#include <util/symbol_table.h>
19+
#include <vector>
1920

2021
class select_pointer_typet;
2122
class pointer_typet;

src/util/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ SRC = arith_tools.cpp \
4141
json_stream.cpp \
4242
lispexpr.cpp \
4343
lispirep.cpp \
44+
mathematical_types.cpp \
4445
memory_info.cpp \
4546
merge_irep.cpp \
4647
message.cpp \

src/util/mathematical_types.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*******************************************************************\
2+
3+
Module: Mathematical types
4+
5+
Author: Daniel Kroening, [email protected]
6+
Maria Svorenova, [email protected]
7+
8+
\*******************************************************************/
9+
10+
/// \file
11+
/// Mathematical types
12+
13+
#include "mathematical_types.h"
14+
15+
/// Returns true if the type is a rational, real, integer, natural, complex,
16+
/// unsignedbv, signedbv, floatbv or fixedbv.
17+
bool is_number(const typet &type)
18+
{
19+
const irep_idt &id = type.id();
20+
return id == ID_rational || id == ID_real || id == ID_integer ||
21+
id == ID_natural || id == ID_complex || id == ID_unsignedbv ||
22+
id == ID_signedbv || id == ID_floatbv || id == ID_fixedbv;
23+
}

src/util/mathematical_types.h

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
/*******************************************************************\
2+
3+
Module: Mathematical types
4+
5+
Author: Daniel Kroening, [email protected]
6+
Maria Svorenova, [email protected]
7+
8+
\*******************************************************************/
9+
10+
/// \file
11+
/// Mathematical types
12+
13+
#ifndef CPROVER_UTIL_MATHEMATICAL_TYPES_H
14+
#define CPROVER_UTIL_MATHEMATICAL_TYPES_H
15+
16+
#include "expr_cast.h"
17+
#include "invariant.h"
18+
#include "type.h"
19+
20+
/// Unbounded, signed integers (mathematical integers, not bitvectors)
21+
class integer_typet : public typet
22+
{
23+
public:
24+
integer_typet() : typet(ID_integer)
25+
{
26+
}
27+
};
28+
29+
/// Natural numbers including zero (mathematical integers, not bitvectors)
30+
class natural_typet : public typet
31+
{
32+
public:
33+
natural_typet() : typet(ID_natural)
34+
{
35+
}
36+
};
37+
38+
/// Unbounded, signed rational numbers
39+
class rational_typet : public typet
40+
{
41+
public:
42+
rational_typet() : typet(ID_rational)
43+
{
44+
}
45+
};
46+
47+
/// Unbounded, signed real numbers
48+
class real_typet : public typet
49+
{
50+
public:
51+
real_typet() : typet(ID_real)
52+
{
53+
}
54+
};
55+
56+
/// A type for mathematical functions (do not confuse with functions/methods
57+
/// in code)
58+
class mathematical_function_typet : public typet
59+
{
60+
public:
61+
// the domain of the function is composed of zero, one, or
62+
// many variables
63+
class variablet : public irept
64+
{
65+
public:
66+
// the identifier is optional
67+
irep_idt get_identifier() const
68+
{
69+
return get(ID_identifier);
70+
}
71+
72+
void set_identifier(const irep_idt &identifier)
73+
{
74+
return set(ID_identifier, identifier);
75+
}
76+
77+
typet &type()
78+
{
79+
return static_cast<typet &>(add(ID_type));
80+
}
81+
82+
const typet &type() const
83+
{
84+
return static_cast<const typet &>(find(ID_type));
85+
}
86+
};
87+
88+
using domaint = std::vector<variablet>;
89+
90+
mathematical_function_typet(const domaint &_domain, const typet &_codomain)
91+
: typet(ID_mathematical_function)
92+
{
93+
subtypes().resize(2);
94+
domain() = _domain;
95+
codomain() = _codomain;
96+
}
97+
98+
domaint &domain()
99+
{
100+
return (domaint &)subtypes()[0].subtypes();
101+
}
102+
103+
const domaint &domain() const
104+
{
105+
return (const domaint &)subtypes()[0].subtypes();
106+
}
107+
108+
variablet &add_variable()
109+
{
110+
auto &d = domain();
111+
d.push_back(variablet());
112+
return d.back();
113+
}
114+
115+
/// Return the codomain, i.e., the set of values that the function maps to
116+
/// (the "target").
117+
typet &codomain()
118+
{
119+
return subtypes()[1];
120+
}
121+
122+
/// \copydoc codomain()
123+
const typet &codomain() const
124+
{
125+
return subtypes()[1];
126+
}
127+
};
128+
129+
/// Check whether a reference to a typet is a \ref mathematical_function_typet.
130+
/// \param type Source type.
131+
/// \return True if \param type is a \ref mathematical_function_typet.
132+
template <>
133+
inline bool can_cast_type<mathematical_function_typet>(const typet &type)
134+
{
135+
return type.id() == ID_mathematical_function;
136+
}
137+
138+
/// \brief Cast a typet to a \ref mathematical_function_typet
139+
///
140+
/// This is an unchecked conversion. \a type must be known to be \ref
141+
/// mathematical_function_typet. Will fail with a precondition violation if type
142+
/// doesn't match.
143+
///
144+
/// \param type Source type.
145+
/// \return Object of type \ref mathematical_function_typet.
146+
inline const mathematical_function_typet &
147+
to_mathematical_function_type(const typet &type)
148+
{
149+
PRECONDITION(can_cast_type<mathematical_function_typet>(type));
150+
return static_cast<const mathematical_function_typet &>(type);
151+
}
152+
153+
/// \copydoc to_mathematical_function_type(const typet &)
154+
inline mathematical_function_typet &to_mathematical_function_type(typet &type)
155+
{
156+
PRECONDITION(can_cast_type<mathematical_function_typet>(type));
157+
return static_cast<mathematical_function_typet &>(type);
158+
}
159+
160+
bool is_number(const typet &type);
161+
162+
#endif // CPROVER_UTIL_MATHEMATICAL_TYPES_H

src/util/simplify_expr_int.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ Author: Daniel Kroening, [email protected]
1818
#include "fixedbv.h"
1919
#include "ieee_float.h"
2020
#include "invariant.h"
21+
#include "mathematical_types.h"
2122
#include "namespace.h"
2223
#include "pointer_offset_size.h"
2324
#include "rational.h"

src/util/std_expr.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ Author: Daniel Kroening, [email protected]
1313
/// \file util/std_expr.h
1414
/// API to expression classes
1515

16+
#include "expr_cast.h"
1617
#include "invariant.h"
18+
#include "mathematical_types.h"
1719
#include "std_types.h"
18-
#include "expr_cast.h"
19-
2020

2121
/// Transition system, consisting of state invariant, initial state predicate,
2222
/// and transition predicate.

src/util/std_types.cpp

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,10 @@ Author: Daniel Kroening, [email protected]
1212

1313
#include "std_types.h"
1414

15-
#include "string2int.h"
1615
#include "arith_tools.h"
16+
#include "namespace.h"
1717
#include "std_expr.h"
18+
#include "string2int.h"
1819

1920
std::size_t fixedbv_typet::get_integer_bits() const
2021
{
@@ -195,3 +196,74 @@ constant_exprt unsignedbv_typet::largest_expr() const
195196
{
196197
return from_integer(largest(), *this);
197198
}
199+
200+
/// Identify whether a given type is constant itself or contains constant
201+
/// components.
202+
/// Examples include:
203+
/// - const int a;
204+
/// - struct contains_constant_pointer { int x; int * const p; };
205+
/// - const int b[3];
206+
/// \param type The type we want to query constness of.
207+
/// \param ns The namespace, needed for resolution of symbols.
208+
/// \return Whether passed in type is const or not.
209+
bool is_constant_or_has_constant_components(
210+
const typet &type,
211+
const namespacet &ns)
212+
{
213+
// Helper function to avoid the code duplication in the branches
214+
// below.
215+
const auto has_constant_components = [&ns](const typet &subtype) -> bool {
216+
if(subtype.id() == ID_struct || subtype.id() == ID_union)
217+
{
218+
const auto &struct_union_type = to_struct_union_type(subtype);
219+
for(const auto &component : struct_union_type.components())
220+
{
221+
if(is_constant_or_has_constant_components(component.type(), ns))
222+
return true;
223+
}
224+
}
225+
return false;
226+
};
227+
228+
// There are 4 possibilities the code below is handling.
229+
// The possibilities are enumerated as comments, to show
230+
// what each code is supposed to be handling. For more
231+
// comprehensive test case for this, take a look at
232+
// regression/cbmc/no_nondet_static/main.c
233+
234+
// const int a;
235+
if(type.get_bool(ID_C_constant))
236+
return true;
237+
238+
// This is a termination condition to break the recursion
239+
// for recursive types such as the following:
240+
// struct list { const int datum; struct list * next; };
241+
// NOTE: the difference between this condition and the previous
242+
// one is that this one always returns.
243+
if(type.id() == ID_pointer)
244+
return type.get_bool(ID_C_constant);
245+
246+
// When we have a case like the following, we don't immediately
247+
// see the struct t. Instead, we only get to see symbol t1, which
248+
// we have to use the namespace to resolve to its definition:
249+
// struct t { const int a; };
250+
// struct t t1;
251+
if(type.id() == ID_symbol_type)
252+
{
253+
const auto &resolved_type = ns.follow(type);
254+
return has_constant_components(resolved_type);
255+
}
256+
257+
// In a case like this, where we see an array (b[3] here), we know that
258+
// the array contains subtypes. We get the first one, and
259+
// then resolve it to its definition through the usage of the namespace.
260+
// struct contains_constant_pointer { int x; int * const p; };
261+
// struct contains_constant_pointer b[3] = { {23, &y}, {23, &y}, {23, &y} };
262+
if(type.has_subtype())
263+
{
264+
const auto &subtype = type.subtype();
265+
return is_constant_or_has_constant_components(subtype, ns);
266+
}
267+
268+
return false;
269+
}

0 commit comments

Comments
 (0)