@@ -6,8 +6,9 @@ Author: Daniel Kroening, kroening@kroening.com
66
77\*******************************************************************/
88
9-
109#include " type.h"
10+ #include " std_types.h"
11+ #include " namespace.h"
1112
1213void typet::copy_to_subtypes (const typet &type)
1314{
@@ -34,3 +35,74 @@ bool is_number(const typet &type)
3435 id==ID_floatbv ||
3536 id==ID_fixedbv;
3637}
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