source: src/AST/Util.cpp @ b7c53a9d

Last change on this file since b7c53a9d was b7c53a9d, checked in by Andrew Beach <ajbeach@…>, 12 months ago

Added a new invariant check and the fixes required to make it pass. Not the new check is by no means exaustive (it doesn't even check every readonly pointer) but it should catch the most common/problematic cases.

  • Property mode set to 100644
File size: 5.0 KB
Line 
1//
2// Cforall Version 1.0.0 Copyright (C) 2019 University of Waterloo
3//
4// The contents of this file are covered under the licence agreement in the
5// file "LICENCE" distributed with Cforall.
6//
7// Util.cpp -- General utilities for working with the AST.
8//
9// Author           : Andrew Beach
10// Created On       : Wed Jan 19  9:46:00 2022
11// Last Modified By : Andrew Beach
12// Last Modified On : Wed May 11 16:16:00 2022
13// Update Count     : 3
14//
15
16#include "Util.hpp"
17
18#include "Node.hpp"
19#include "ParseNode.hpp"
20#include "Pass.hpp"
21#include "TranslationUnit.hpp"
22
23#include <vector>
24
25namespace ast {
26
27namespace {
28
29/// Check that ast::ptr/strong references do not form a cycle.
30struct NoStrongCyclesCore {
31        std::vector<const Node *> parents;
32
33        void previsit( const Node * node ) {
34                for ( auto & parent : parents ) {
35                        assert( parent != node );
36                }
37                parents.push_back( node );
38        }
39
40        void postvisit( const Node * node ) {
41                assert( !parents.empty() );
42                assert( parents.back() == node );
43                parents.pop_back();
44        }
45};
46
47/// Check that every note that can has a set CodeLocation.
48void isCodeLocationSet( const ParseNode * node ) {
49        assert( node->location.isSet() );
50}
51
52void areLabelLocationsSet( const Stmt * stmt ) {
53        for ( const Label& label : stmt->labels ) {
54                assert( label.location.isSet() );
55        }
56}
57
58/// Make sure the reference counts are in a valid combination.
59void isStable( const Node * node ) {
60        assert( node->isStable() );
61}
62
63/// Check that a FunctionDecl is synchronized with it's FunctionType.
64void functionDeclMatchesType( const FunctionDecl * decl ) {
65        // The type is a cache of sorts, if it is missing that is only a
66        // problem if isTypeFixed is set.
67        if ( decl->isTypeFixed ) {
68                assert( decl->type );
69        } else if ( !decl->type ) {
70                return;
71        }
72
73        const FunctionType * type = decl->type;
74
75        // Check that `type->forall` corresponds with `decl->type_params`.
76        assert( type->forall.size() == decl->type_params.size() );
77        // Check that `type->assertions` corresponds with `decl->assertions`.
78        assert( type->assertions.size() == decl->assertions.size() );
79        // Check that `type->params` corresponds with `decl->params`.
80        assert( type->params.size() == decl->params.size() );
81        // Check that `type->returns` corresponds with `decl->returns`.
82        assert( type->returns.size() == decl->returns.size() );
83}
84
85/// Check that the MemberExpr has an aggregate type and matching member.
86void memberMatchesAggregate( const MemberExpr * expr ) {
87        const Type * aggrType = expr->aggregate->result->stripReferences();
88        const AggregateDecl * decl = nullptr;
89        if ( auto inst = dynamic_cast<const StructInstType *>( aggrType ) ) {
90                decl = inst->base;
91        } else if ( auto inst = dynamic_cast<const UnionInstType *>( aggrType ) ) {
92                decl = inst->base;
93        }
94        assertf( decl, "Aggregate of member not correct type." );
95
96        for ( auto aggrMember : decl->members ) {
97                if ( expr->member == aggrMember ) {
98                        return;
99                }
100        }
101        assertf( false, "Member not found." );
102}
103
104/// Check for Floating Nodes:
105/// Every node should be reachable from a root (the TranslationUnit) via a
106/// chain of structural references (tracked with ptr). This cannot check all
107/// of that, it just checks if a given node's field has a strong reference.
108template<typename node_t, typename field_t>
109void noFloatingNode( const node_t * node, field_t node_t::*field_ptr ) {
110        const field_t & field = node->*field_ptr;
111        if ( nullptr == field ) return;
112        assertf( field->isManaged(), "Floating node found." );
113}
114
115struct InvariantCore {
116        // To save on the number of visits: this is a kind of composed core.
117        // None of the passes should make changes so ordering doesn't matter.
118        NoStrongCyclesCore no_strong_cycles;
119
120        void previsit( const Node * node ) {
121                no_strong_cycles.previsit( node );
122                isStable( node );
123        }
124
125        void previsit( const ParseNode * node ) {
126                previsit( (const Node *)node );
127                isCodeLocationSet( node );
128        }
129
130        void previsit( const FunctionDecl * node ) {
131                previsit( (const ParseNode *)node );
132                functionDeclMatchesType( node );
133        }
134
135        void previsit( const Stmt * node ) {
136                previsit( (const ParseNode *)node );
137                areLabelLocationsSet( node );
138        }
139
140        void previsit( const VariableExpr * node ) {
141                previsit( (const ParseNode *)node );
142                noFloatingNode( node, &VariableExpr::var );
143        }
144
145        void previsit( const MemberExpr * node ) {
146                previsit( (const ParseNode *)node );
147                memberMatchesAggregate( node );
148        }
149
150        void previsit( const StructInstType * node ) {
151                previsit( (const Node *)node );
152                noFloatingNode( node, &StructInstType::base );
153        }
154
155        void previsit( const UnionInstType * node ) {
156                previsit( (const Node *)node );
157                noFloatingNode( node, &UnionInstType::base );
158        }
159
160        void previsit( const EnumInstType * node ) {
161                previsit( (const Node *)node );
162                noFloatingNode( node, &EnumInstType::base );
163        }
164
165        void previsit( const TypeInstType * node ) {
166                previsit( (const Node *)node );
167                noFloatingNode( node, &TypeInstType::base );
168        }
169
170        void postvisit( const Node * node ) {
171                no_strong_cycles.postvisit( node );
172        }
173};
174
175} // namespace
176
177void checkInvariants( TranslationUnit & transUnit ) {
178        ast::Pass<InvariantCore>::run( transUnit );
179}
180
181} // namespace ast
Note: See TracBrowser for help on using the repository browser.