source: src/Validate/ForallPointerDecay.cpp @ 0e8f4c6

Last change on this file since 0e8f4c6 was b7c53a9d, checked in by Andrew Beach <ajbeach@…>, 16 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: 7.3 KB
Line 
1//
2// Cforall Version 1.0.0 Copyright (C) 2018 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// ForallPointerDecay.cpp --
8//
9// Author           : Andrew Beach
10// Created On       : Tue Dec  7 16:15:00 2021
11// Last Modified By : Andrew Beach
12// Last Modified On : Sat Apr 23 13:10:00 2022
13// Update Count     : 1
14//
15
16#include "ForallPointerDecay.hpp"
17
18#include "AST/Copy.hpp"
19#include "AST/Decl.hpp"
20#include "AST/DeclReplacer.hpp"
21#include "AST/Pass.hpp"
22#include "CodeGen/OperatorTable.h"
23#include "Common/CodeLocation.h"
24#include "Common/ToString.hpp"
25#include "Common/utility.h"
26#include "SymTab/FixFunction.h"
27
28namespace Validate {
29
30namespace {
31
32// Create a function type only using information on the FunctionDecl.
33ast::FunctionType * makeFuncType( const ast::FunctionDecl * decl ) {
34        auto type = new ast::FunctionType( decl->type->isVarArgs );
35        for ( auto & param : decl->params ) {
36                type->params.emplace_back( param->get_type() );
37        }
38        for ( auto & ret : decl->returns ) {
39                type->returns.emplace_back( ret->get_type() );
40        }
41        for ( auto & type_param : decl->type_params ) {
42                type->forall.emplace_back(
43                        new ast::TypeInstType( type_param ) );
44        }
45        for ( auto & assertion : decl->assertions ) {
46                type->assertions.emplace_back( new ast::VariableExpr(
47                        assertion->location, assertion ) );
48        }
49        return type;
50}
51
52ast::FunctionDecl * updateAssertions( ast::FunctionDecl * decl ) {
53        auto type = ast::mutate( decl->type.get() );
54        type->assertions.clear();
55        type->assertions.reserve( decl->assertions.size() );
56        for ( auto & assertion : decl->assertions ) {
57                type->assertions.emplace_back(
58                        new ast::VariableExpr( decl->location, assertion ) );
59        }
60        decl->type = type;
61        return decl;
62}
63
64// Component Passes:
65/// Expand assertions from a trait instance,
66/// performing appropriate type variable substitutions.
67struct TraitExpander final {
68        using AssertionList = std::vector<ast::ptr<ast::DeclWithType>>;
69
70        static AssertionList expandTrait( const ast::TraitInstType * inst ) {
71                assertf( inst->base, "Trait instance not linked to base trait: %s",
72                        toCString( inst ) );
73                AssertionList assertions;
74                // Substitute trait decl parameters for instance parameters.
75                ast::TypeSubstitution sub( inst->base->params, inst->params );
76                for ( const ast::ptr<ast::Decl> & decl : inst->base->members ) {
77                        ast::ptr<ast::DeclWithType> copy =
78                                ast::deepCopy( decl.strict_as<ast::DeclWithType>() );
79
80                        int count = sub.apply( copy );
81                        (void)count;
82
83                        // Update the type (type substution does not seem to cover it).
84                        if ( auto func = copy.as<ast::FunctionDecl>() ) {
85                                auto mut = ast::mutate( func );
86                                mut->type = makeFuncType( func );
87                                copy = mut;
88                        }
89                        assertions.push_back( copy );
90                }
91                return assertions;
92        }
93
94        static AssertionList expandAssertions( const AssertionList & old ) {
95                AssertionList assertions;
96                for ( const ast::ptr<ast::DeclWithType> & decl : old ) {
97                        if ( auto traitInst = dynamic_cast<const ast::TraitInstType *>(
98                                        decl->get_type() ) ) {
99                                auto moreAsserts = expandTrait( traitInst );
100                                splice( assertions, moreAsserts );
101                        } else {
102                                assertions.push_back( decl );
103                        }
104                }
105                return assertions;
106        }
107
108        using TypeDeclVec = std::vector<ast::ptr<ast::TypeDecl>>;
109
110        static TypeDeclVec expandTypeDecls( const TypeDeclVec & old ) {
111                TypeDeclVec typeDecls;
112                typeDecls.reserve( old.size() );
113                for ( const ast::TypeDecl * typeDecl : old ) {
114                        typeDecls.push_back( ast::mutate_field( typeDecl,
115                                &ast::TypeDecl::assertions,
116                                expandAssertions( typeDecl->assertions ) ) );
117                }
118                return typeDecls;
119        }
120
121        const ast::FunctionDecl * postvisit( const ast::FunctionDecl * decl ) {
122                if ( decl->assertions.empty() ) {
123                        return decl;
124                }
125                auto mut = ast::mutate( decl );
126                mut->assertions = expandAssertions( decl->assertions );
127                // Update the assertion list on the type as well.
128                return updateAssertions( mut );
129        }
130
131        const ast::StructDecl * previsit( const ast::StructDecl * decl ) {
132                if ( decl->params.empty() ) {
133                        return decl;
134                }
135                return ast::mutate_field( decl, &ast::StructDecl::params,
136                        expandTypeDecls( decl->params ) );
137        }
138
139        const ast::UnionDecl * previsit( const ast::UnionDecl * decl ) {
140                if ( decl->params.empty() ) {
141                        return decl;
142                }
143                return ast::mutate_field( decl, &ast::UnionDecl::params,
144                        expandTypeDecls( decl->params ) );
145        }
146};
147
148std::vector<ast::ptr<ast::DeclWithType>> fixAssertionList(
149                const ast::ParseNode * node,
150                const std::vector<ast::ptr<ast::DeclWithType>> & assertions ) {
151        std::vector<ast::ptr<ast::DeclWithType>> ret;
152        ret.reserve( assertions.size() );
153        for ( const auto & assn : assertions ) {
154                bool isVoid = false;
155                ret.push_back( SymTab::fixFunction( assn, isVoid ) );
156                if ( isVoid ) {
157                        SemanticError( node->location, node,
158                                "invalid type void in assertion of function " );
159                }
160        }
161        return ret;
162}
163
164std::vector<ast::ptr<ast::TypeDecl>> fixTypeDeclList(
165                const ast::ParseNode * node,
166                const std::vector<ast::ptr<ast::TypeDecl>> & type_params ) {
167        std::vector<ast::ptr<ast::TypeDecl>> ret;
168        ret.reserve( type_params.size() );
169        for ( const ast::TypeDecl * type_param : type_params ) {
170                auto mutParam = ast::mutate( type_param );
171                mutParam->assertions = fixAssertionList( node, mutParam->assertions );
172                ret.push_back( mutParam );
173        }
174        return ret;
175}
176
177struct AssertionFunctionFixer final {
178        const ast::FunctionDecl * previsit( const ast::FunctionDecl * decl ) {
179                if ( decl->assertions.empty() ) {
180                        return decl;
181                }
182                return ast::mutate_field( decl, &ast::FunctionDecl::assertions,
183                        fixAssertionList( decl, decl->assertions ) );
184        }
185
186        const ast::FunctionDecl * postvisit( const ast::FunctionDecl * decl ) {
187                if ( decl->assertions.empty() ) {
188                        return decl;
189                }
190                return updateAssertions( mutate( decl ) );
191        }
192
193        const ast::StructDecl * previsit( const ast::StructDecl * decl ) {
194                if ( decl->params.empty() ) {
195                        return decl;
196                }
197                return ast::mutate_field( decl, &ast::StructDecl::params,
198                        fixTypeDeclList( decl, decl->params ) );
199        }
200
201        const ast::UnionDecl * previsit( const ast::UnionDecl * decl ) {
202                if ( decl->params.empty() ) {
203                        return decl;
204                }
205                return ast::mutate_field( decl, &ast::UnionDecl::params,
206                        fixTypeDeclList( decl, decl->params ) );
207        }
208};
209
210struct OperatorChecker final {
211        void previsit( const ast::ObjectDecl * obj ) {
212                if ( !CodeGen::isOperator( obj->name ) ) return;
213                auto type = obj->type->stripDeclarator();
214                if ( dynamic_cast< const ast::FunctionType * >( type ) ) return;
215                SemanticError( obj->location,
216                        toCString( "operator ", obj->name.c_str(), " is not "
217                        "a function or function pointer." ) );
218        }
219};
220
221struct UniqueFixCore final {
222        const ast::DeclWithType * postvisit( const ast::DeclWithType * decl ) {
223                if ( decl->uniqueId ) {
224                        return decl;
225                } else {
226                        auto mut = ast::mutate( decl );
227                        mut->fixUniqueId();
228                        return mut;
229                }
230        }
231};
232
233} // namespace
234
235void decayForallPointers( ast::TranslationUnit & transUnit ) {
236        ast::Pass<TraitExpander>::run( transUnit );
237        ast::Pass<AssertionFunctionFixer>::run( transUnit );
238        ast::Pass<OperatorChecker>::run( transUnit );
239        ast::Pass<UniqueFixCore>::run( transUnit );
240}
241
242std::vector<ast::ptr<ast::DeclWithType>> expandAssertions(
243                std::vector<ast::ptr<ast::DeclWithType>> const & old ) {
244        return TraitExpander::expandAssertions( old );
245}
246
247} // namespace Validate
248
249// Local Variables: //
250// tab-width: 4 //
251// mode: c++ //
252// compile-command: "make install" //
253// End: //
Note: See TracBrowser for help on using the repository browser.