6
6
7
7
\*******************************************************************/
8
8
9
-
10
9
#include " type.h"
10
+ #include " std_types.h"
11
+ #include " namespace.h"
11
12
12
13
void typet::copy_to_subtypes (const typet &type)
13
14
{
@@ -34,3 +35,74 @@ bool is_number(const typet &type)
34
35
id==ID_floatbv ||
35
36
id==ID_fixedbv;
36
37
}
38
+
39
+ // / Identify if a given type is constant itself or
40
+ // / contains constant components. Examples include:
41
+ // / - const int a;
42
+ // / - struct contains_constant_pointer { int x; int * const p; };
43
+ // / - const int b[3];
44
+ // / \param type The type we want to query constness of.
45
+ // / \param ns The namespace, needed for resolution of symbols.
46
+ // / \return Whether passed in type is const or not.
47
+ bool is_constant_or_has_constant_components (
48
+ const typet &type, const namespacet &ns)
49
+ {
50
+ // Helper function to avoid the code duplication in the branches
51
+ // below.
52
+ const auto has_constant_components =
53
+ [&ns](const typet &subtype) -> bool
54
+ {
55
+ if (subtype.id () == ID_struct || subtype.id () == ID_union)
56
+ {
57
+ const auto &struct_union_type = to_struct_union_type (subtype);
58
+ for (const auto &component : struct_union_type.components ())
59
+ {
60
+ if (is_constant_or_has_constant_components (component.type (), ns))
61
+ return true ;
62
+ }
63
+ }
64
+ return false ;
65
+ };
66
+
67
+ // There are 4 possibilities the code below is handling.
68
+ // The possibilities are enumerated as comments, to show
69
+ // what each code is supposed to be handling. For more
70
+ // comprehensive test case for this, take a look at
71
+ // regression/cbmc/no_nondet_static/main.c
72
+
73
+ // const int a;
74
+ if (type.get_bool (ID_C_constant))
75
+ return true ;
76
+
77
+ // This is a termination condition to break the recursion
78
+ // for recursive types such as the following:
79
+ // struct list { const int datum; struct list * next; };
80
+ // NOTE: the difference between this condition and the previous
81
+ // one is that this one always returns.
82
+ if (type.id ()==ID_pointer)
83
+ return type.get_bool (ID_C_constant);
84
+
85
+ // When we have a case like the following, we don't immediately
86
+ // see the struct t. Instead, we only get to see symbol t1, which
87
+ // we have to use the namespace to resolve to its definition:
88
+ // struct t { const int a; };
89
+ // struct t t1;
90
+ if (type.id () == ID_symbol)
91
+ {
92
+ const auto &resolved_type = ns.follow (type);
93
+ return has_constant_components (resolved_type);
94
+ }
95
+
96
+ // In a case like this, where we see an array (b[3] here), we know that
97
+ // the array contains subtypes. We get the first one, and
98
+ // then resolve it to its definition through the usage of the namespace.
99
+ // struct contains_constant_pointer { int x; int * const p; };
100
+ // struct contains_constant_pointer b[3] = { {23, &y}, {23, &y}, {23, &y} };
101
+ if (type.has_subtype ())
102
+ {
103
+ const auto &subtype = type.subtype ();
104
+ return is_constant_or_has_constant_components (subtype, ns);
105
+ }
106
+
107
+ return false ;
108
+ }
0 commit comments