diff --git a/src/util/c_types.h b/src/util/c_types.h index 7fbad42c800..a16151d17d8 100644 --- a/src/util/c_types.h +++ b/src/util/c_types.h @@ -195,11 +195,11 @@ inline union_typet &to_union_type(typet &type) } /// A union tag type, i.e., \ref union_typet with an identifier -class union_tag_typet : public tag_typet +class union_tag_typet : public struct_or_union_tag_typet { public: explicit union_tag_typet(const irep_idt &identifier) - : tag_typet(ID_union_tag, identifier) + : struct_or_union_tag_typet(ID_union_tag, identifier) { } }; diff --git a/src/util/namespace.cpp b/src/util/namespace.cpp index fcdf4b1465b..069c1e71806 100644 --- a/src/util/namespace.cpp +++ b/src/util/namespace.cpp @@ -92,6 +92,15 @@ namespace_baset::follow_tag(const c_enum_tag_typet &src) const return to_c_enum_type(symbol.type); } +const struct_union_typet &namespace_baset::follow_struct_or_union_tag( + const struct_or_union_tag_typet &src) const +{ + const symbolt &symbol = lookup(src.get_identifier()); + CHECK_RETURN(symbol.is_type); + CHECK_RETURN(symbol.type.id() == ID_struct || symbol.type.id() == ID_union); + return to_struct_union_type(symbol.type); +} + /// Follow macros to their values in a given expression. /// \param expr: The expression to follow macros in. void namespace_baset::follow_macros(exprt &expr) const diff --git a/src/util/namespace.h b/src/util/namespace.h index 8328e1b815c..0b7d05f72a3 100644 --- a/src/util/namespace.h +++ b/src/util/namespace.h @@ -21,9 +21,11 @@ class symbol_exprt; class tag_typet; class union_typet; class struct_typet; +class struct_union_typet; class c_enum_typet; class union_tag_typet; class struct_tag_typet; +class struct_or_union_tag_typet; class c_enum_tag_typet; class symbol_table_baset; @@ -68,6 +70,10 @@ class namespace_baset const struct_typet &follow_tag(const struct_tag_typet &) const; const c_enum_typet &follow_tag(const c_enum_tag_typet &) const; + /// Resolve a `struct_tag_typet` or `union_tag_typet` to the complete version. + const struct_union_typet & + follow_struct_or_union_tag(const struct_or_union_tag_typet &) const; + /// Returns the minimal integer n such that there is no symbol (in any of the /// symbol tables) whose name is of the form "An" where A is \p prefix. /// The intended use case is finding the next available symbol name for a diff --git a/src/util/std_types.h b/src/util/std_types.h index 314bda93afd..ad314267454 100644 --- a/src/util/std_types.h +++ b/src/util/std_types.h @@ -444,12 +444,56 @@ inline tag_typet &to_tag_type(typet &type) return static_cast(type); } +/// A struct or union tag type. This is only to be used to create type-safe / +/// APIs, no instances of this one can be created directly, use \ref +/// struct_tag_typet or \ref union_tag_typet when creating objects. +class struct_or_union_tag_typet : public tag_typet +{ +protected: + struct_or_union_tag_typet(const irep_idt &id, const irep_idt &identifier) + : tag_typet(id, identifier) + { + PRECONDITION(id == ID_struct_tag || id == ID_union_tag); + } +}; + +/// Check whether a reference to a typet is a \ref struct_or_union_tag_typet. +/// \param type: Source type. +/// \return True if \p type is a \ref struct_or_union_tag_typet. +template <> +inline bool can_cast_type(const typet &type) +{ + return type.id() == ID_struct_tag || type.id() == ID_union_tag; +} + +/// \brief Cast a typet to a \ref struct_or_union_tag_typet +/// +/// This is an unchecked conversion. \a type must be known to be \ref +/// struct_or_union_tag_typet. Will fail with a precondition violation if type +/// doesn't match. +/// +/// \param type: Source type. +/// \return Object of type \ref struct_or_union_tag_typet +inline const struct_or_union_tag_typet & +to_struct_or_union_tag_type(const typet &type) +{ + PRECONDITION(can_cast_type(type)); + return static_cast(type); +} + +/// \copydoc to_struct_or_union_tag_type(const typet &) +inline struct_or_union_tag_typet &to_struct_or_union_tag_type(typet &type) +{ + PRECONDITION(can_cast_type(type)); + return static_cast(type); +} + /// A struct tag type, i.e., \ref struct_typet with an identifier -class struct_tag_typet:public tag_typet +class struct_tag_typet : public struct_or_union_tag_typet { public: - explicit struct_tag_typet(const irep_idt &identifier): - tag_typet(ID_struct_tag, identifier) + explicit struct_tag_typet(const irep_idt &identifier) + : struct_or_union_tag_typet(ID_struct_tag, identifier) { } };